Exemple #1
0
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
		const char *userdefevname, const char *extra, struct ast_channel *peer2)
{
	struct timeval eventtime;
	struct ast_event *ev;
	const char *peername = "";
	struct ast_channel *peer;

	ast_channel_lock(chan);
	peer = ast_bridged_channel(chan);
	if (peer) {
		ast_channel_ref(peer);
	}
	ast_channel_unlock(chan);

	/* Make sure a reload is not occurring while we're checking to see if this
	 * is an event that we care about.  We could lose an important event in this
	 * process otherwise. */
	ast_mutex_lock(&reload_lock);

	if (!cel_enabled || !ast_cel_track_event(event_type)) {
		ast_mutex_unlock(&reload_lock);
		if (peer) {
			ast_channel_unref(peer);
		}
		return 0;
	}

	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
		char *app;
		if (!(app = ao2_find(appset, (char *) chan->appl, OBJ_POINTER))) {
			ast_mutex_unlock(&reload_lock);
			if (peer) {
				ast_channel_unref(peer);
			}
			return 0;
		}
		ao2_ref(app, -1);
	}

	ast_mutex_unlock(&reload_lock);

	if (peer) {
		ast_channel_lock(peer);
		peername = ast_strdupa(peer->name);
		ast_channel_unlock(peer);
	} else if (peer2) {
		ast_channel_lock(peer2);
		peername = ast_strdupa(peer2->name);
		ast_channel_unlock(peer2);
	}

	if (!userdefevname) {
		userdefevname = "";
	}

	if (!extra) {
		extra = "";
	}

	eventtime = ast_tvnow();

	ast_channel_lock(chan);

	ev = ast_event_new(AST_EVENT_CEL,
		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, ""),
		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->caller.ani.number.valid, chan->caller.ani.number.str, ""),
		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
			S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, ""),
		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
			S_OR(chan->dialed.number.str, ""),
		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, chan->exten,
		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, chan->context,
		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, chan->name,
		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->appl, ""),
		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(chan->data, ""),
		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, chan->amaflags,
		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, chan->accountcode,
		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, chan->peeraccount,
		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, chan->uniqueid,
		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, chan->linkedid,
		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, chan->userfield,
		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
		AST_EVENT_IE_END);

	ast_channel_unlock(chan);

	if (peer) {
		peer = ast_channel_unref(peer);
	}

	if (ev && ast_event_queue(ev)) {
		ast_event_destroy(ev);
		return -1;
	}

	return 0;
}
Exemple #2
0
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
{
	int res = 0;
	struct ast_channel *peer = NULL;

	ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan));

	ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
	res = ast_audiohook_attach(autochan->chan, audiohook);

	if (!res && ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
		ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
	}
	return res;
}
/*!
 * \internal
 * \note This function assumes that we're only called from the "outbound" local channel side
 *
 * \note it is assummed p is locked and reffed before entering this function
 */
static void check_bridge(struct ast_channel *ast, struct local_pvt *p)
{
	struct ast_channel *owner;
	struct ast_channel *chan;
	struct ast_channel *bridged_chan;
	struct ast_frame *f;

	/* Do a few conditional checks early on just to see if this optimization is possible */
	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
		|| !p->chan || !p->owner) {
		return;
	}

	/* Safely get the channel bridged to p->chan */
	chan = ast_channel_ref(p->chan);

	ao2_unlock(p); /* don't call bridged channel with the pvt locked */
	bridged_chan = ast_bridged_channel(chan);
	ao2_lock(p);

	chan = ast_channel_unref(chan);

	/* since we had to unlock p to get the bridged chan, validate our
	 * data once again and verify the bridged channel is what we expect
	 * it to be in order to perform this optimization */
	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
		|| !p->chan || !p->owner
		|| (ast_channel_internal_bridged_channel(p->chan) != bridged_chan)) {
		return;
	}

	/* only do the masquerade if we are being called on the outbound channel,
	   if it has been bridged to another channel and if there are no pending
	   frames on the owner channel (because they would be transferred to the
	   outbound channel during the masquerade)
	*/
	if (!ast_channel_internal_bridged_channel(p->chan) /* Not ast_bridged_channel!  Only go one step! */
		|| !AST_LIST_EMPTY(ast_channel_readq(p->owner))
		|| ast != p->chan /* Sanity check (should always be false) */) {
		return;
	}

	/* Masquerade bridged channel into owner */
	/* Lock everything we need, one by one, and give up if
	   we can't get everything.  Remember, we'll get another
	   chance in just a little bit */
	if (ast_channel_trylock(ast_channel_internal_bridged_channel(p->chan))) {
		return;
	}
	if (ast_check_hangup(ast_channel_internal_bridged_channel(p->chan))
		|| ast_channel_trylock(p->owner)) {
		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
		return;
	}

	/*
	 * At this point we have 4 locks:
	 * p, p->chan (same as ast), p->chan->_bridge, p->owner
	 *
	 * Flush a voice or video frame on the outbound channel to make
	 * the queue empty faster so we can get optimized out.
	 */
	f = AST_LIST_FIRST(ast_channel_readq(p->chan));
	if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
		AST_LIST_REMOVE_HEAD(ast_channel_readq(p->chan), frame_list);
		ast_frfree(f);
		f = AST_LIST_FIRST(ast_channel_readq(p->chan));
	}

	if (f
		|| ast_check_hangup(p->owner)
		|| ast_channel_masquerade(p->owner, ast_channel_internal_bridged_channel(p->chan))) {
		ast_channel_unlock(p->owner);
		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
		return;
	}

	/* Masquerade got setup. */
	ast_debug(4, "Masquerading %s <- %s\n",
		ast_channel_name(p->owner),
		ast_channel_name(ast_channel_internal_bridged_channel(p->chan)));
	if (ast_channel_monitor(p->owner)
		&& !ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan))) {
		struct ast_channel_monitor *tmp;

		/* If a local channel is being monitored, we don't want a masquerade
		 * to cause the monitor to go away. Since the masquerade swaps the monitors,
		 * pre-swapping the monitors before the masquerade will ensure that the monitor
		 * ends up where it is expected.
		 */
		tmp = ast_channel_monitor(p->owner);
		ast_channel_monitor_set(p->owner, ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan)));
		ast_channel_monitor_set(ast_channel_internal_bridged_channel(p->chan), tmp);
	}
	if (ast_channel_audiohooks(p->chan)) {
		struct ast_audiohook_list *audiohooks_swapper;

		audiohooks_swapper = ast_channel_audiohooks(p->chan);
		ast_channel_audiohooks_set(p->chan, ast_channel_audiohooks(p->owner));
		ast_channel_audiohooks_set(p->owner, audiohooks_swapper);
	}

	/* If any Caller ID was set, preserve it after masquerade like above. We must check
	 * to see if Caller ID was set because otherwise we'll mistakingly copy info not
	 * set from the dialplan and will overwrite the real channel Caller ID. The reason
	 * for this whole preswapping action is because the Caller ID is set on the channel
	 * thread (which is the to be masqueraded away local channel) before both local
	 * channels are optimized away.
	 */
	if (ast_channel_caller(p->owner)->id.name.valid || ast_channel_caller(p->owner)->id.number.valid
		|| ast_channel_caller(p->owner)->id.subaddress.valid || ast_channel_caller(p->owner)->ani.name.valid
		|| ast_channel_caller(p->owner)->ani.number.valid || ast_channel_caller(p->owner)->ani.subaddress.valid) {
		SWAP(*ast_channel_caller(p->owner), *ast_channel_caller(ast_channel_internal_bridged_channel(p->chan)));
	}
	if (ast_channel_redirecting(p->owner)->from.name.valid || ast_channel_redirecting(p->owner)->from.number.valid
		|| ast_channel_redirecting(p->owner)->from.subaddress.valid || ast_channel_redirecting(p->owner)->to.name.valid
		|| ast_channel_redirecting(p->owner)->to.number.valid || ast_channel_redirecting(p->owner)->to.subaddress.valid) {
		SWAP(*ast_channel_redirecting(p->owner), *ast_channel_redirecting(ast_channel_internal_bridged_channel(p->chan)));
	}
	if (ast_channel_dialed(p->owner)->number.str || ast_channel_dialed(p->owner)->subaddress.valid) {
		SWAP(*ast_channel_dialed(p->owner), *ast_channel_dialed(ast_channel_internal_bridged_channel(p->chan)));
	}
	ast_app_group_update(p->chan, p->owner);
	ast_set_flag(p, LOCAL_ALREADY_MASQED);

	ast_channel_unlock(p->owner);
	ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));

	/* Do the masquerade now. */
	owner = ast_channel_ref(p->owner);
	ao2_unlock(p);
	ast_channel_unlock(ast);
	ast_do_masquerade(owner);
	ast_channel_unref(owner);
	ast_channel_lock(ast);
	ao2_lock(p);
}
static void *mixmonitor_thread(void *obj) 
{
	struct mixmonitor *mixmonitor = obj;

	struct ast_filestream **fs = NULL;
	struct ast_filestream **fs_read = NULL;
	struct ast_filestream **fs_write = NULL;

	unsigned int oflags;
	int errflag = 0;
	struct ast_format format_slin;

	ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);

	fs = &mixmonitor->mixmonitor_ds->fs;
	fs_read = &mixmonitor->mixmonitor_ds->fs_read;
	fs_write = &mixmonitor->mixmonitor_ds->fs_write;

	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
	mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
	mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
	mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);

	ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);

	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);


	/* The audiohook must enter and exit the loop locked */
	ast_audiohook_lock(&mixmonitor->audiohook);
	while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
		struct ast_frame *fr = NULL;
		struct ast_frame *fr_read = NULL;
		struct ast_frame *fr_write = NULL;

		if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
						&fr_read, &fr_write))) {
			ast_audiohook_trigger_wait(&mixmonitor->audiohook);

			if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
				break;
			}
			continue;
		}

		/* audiohook lock is not required for the next block.
		 * Unlock it, but remember to lock it before looping or exiting */
		ast_audiohook_unlock(&mixmonitor->audiohook);

		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
			ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);

			/* Write out the frame(s) */
			if ((*fs_read) && (fr_read)) {
				struct ast_frame *cur;

				for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
					ast_writestream(*fs_read, cur);
				}
			}

			if ((*fs_write) && (fr_write)) {
				struct ast_frame *cur;

				for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
					ast_writestream(*fs_write, cur);
				}
			}

			if ((*fs) && (fr)) {
				struct ast_frame *cur;

				for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
					ast_writestream(*fs, cur);
				}
			}
			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
		}
		/* All done! free it. */
		if (fr) {
			ast_frame_free(fr, 0);
		}
		if (fr_read) {
			ast_frame_free(fr_read, 0);
		}
		if (fr_write) {
			ast_frame_free(fr_write, 0);
		}

		fr = NULL;
		fr_write = NULL;
		fr_read = NULL;

		ast_audiohook_lock(&mixmonitor->audiohook);
	}
	ast_audiohook_unlock(&mixmonitor->audiohook);

	ast_autochan_destroy(mixmonitor->autochan);

	/* Datastore cleanup.  close the filestream and wait for ds destruction */
	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
	mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
	if (!mixmonitor->mixmonitor_ds->destruction_ok) {
		ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
	}
	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);

	/* kill the audiohook */
	destroy_monitor_audiohook(mixmonitor);

	if (mixmonitor->post_process) {
		ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
		ast_safe_system(mixmonitor->post_process);
	}

	ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
	mixmonitor_free(mixmonitor);
	return NULL;
}
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);
}
Exemple #6
0
static int func_channel_read(struct ast_channel *chan, const char *function,
                             char *data, char *buf, size_t len)
{
    int ret = 0;
    char tmp[512];
    struct ast_format_cap *tmpcap;

    if (!strcasecmp(data, "audionativeformat")) {
        if ((tmpcap = ast_format_cap_get_type(chan->nativeformats, AST_FORMAT_TYPE_AUDIO))) {
            ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len);
            tmpcap = ast_format_cap_destroy(tmpcap);
        }
    } else if (!strcasecmp(data, "videonativeformat")) {
        if ((tmpcap = ast_format_cap_get_type(chan->nativeformats, AST_FORMAT_TYPE_VIDEO))) {
            ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len);
            tmpcap = ast_format_cap_destroy(tmpcap);
        }
    } else if (!strcasecmp(data, "audioreadformat")) {
        ast_copy_string(buf, ast_getformatname(&chan->readformat), len);
    } else if (!strcasecmp(data, "audiowriteformat")) {
        ast_copy_string(buf, ast_getformatname(&chan->writeformat), len);
#ifdef CHANNEL_TRACE
    } else if (!strcasecmp(data, "trace")) {
        ast_channel_lock(chan);
        ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
        ast_channel_unlock(chan);
#endif
    } else if (!strcasecmp(data, "tonezone") && chan->zone)
        locked_copy_string(chan, buf, chan->zone->country, len);
    else if (!strcasecmp(data, "language"))
        locked_copy_string(chan, buf, chan->language, len);
    else if (!strcasecmp(data, "musicclass"))
        locked_copy_string(chan, buf, chan->musicclass, len);
    else if (!strcasecmp(data, "name")) {
        locked_copy_string(chan, buf, chan->name, len);
    } else if (!strcasecmp(data, "parkinglot"))
        locked_copy_string(chan, buf, chan->parkinglot, len);
    else if (!strcasecmp(data, "state"))
        locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
    else if (!strcasecmp(data, "channeltype"))
        locked_copy_string(chan, buf, chan->tech->type, len);
    else if (!strcasecmp(data, "accountcode"))
        locked_copy_string(chan, buf, chan->accountcode, len);
    else if (!strcasecmp(data, "checkhangup")) {
        ast_channel_lock(chan);
        ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len);
        ast_channel_unlock(chan);
    } else if (!strcasecmp(data, "peeraccount"))
        locked_copy_string(chan, buf, chan->peeraccount, len);
    else if (!strcasecmp(data, "hangupsource"))
        locked_copy_string(chan, buf, chan->hangupsource, len);
    else if (!strcasecmp(data, "appname") && chan->appl)
        locked_copy_string(chan, buf, chan->appl, len);
    else if (!strcasecmp(data, "appdata") && chan->data)
        locked_copy_string(chan, buf, chan->data, len);
    else if (!strcasecmp(data, "exten") && chan->data)
        locked_copy_string(chan, buf, chan->exten, len);
    else if (!strcasecmp(data, "context") && chan->data)
        locked_copy_string(chan, buf, chan->context, len);
    else if (!strcasecmp(data, "userfield") && chan->data)
        locked_copy_string(chan, buf, chan->userfield, len);
    else if (!strcasecmp(data, "channame") && chan->data)
        locked_copy_string(chan, buf, chan->name, len);
    else if (!strcasecmp(data, "linkedid")) {
        ast_channel_lock(chan);
        if (ast_strlen_zero(chan->linkedid)) {
            /* fall back on the channel's uniqueid if linkedid is unset */
            ast_copy_string(buf, chan->uniqueid, len);
        }
        else {
            ast_copy_string(buf, chan->linkedid, len);
        }
        ast_channel_unlock(chan);
    } else if (!strcasecmp(data, "peer")) {
        struct ast_channel *p;
        ast_channel_lock(chan);
        p = ast_bridged_channel(chan);
        if (p || chan->tech || chan->cdr) /* dummy channel? if so, we hid the peer name in the language */
            ast_copy_string(buf, (p ? p->name : ""), len);
        else {
            /* a dummy channel can still pass along bridged peer info via
                           the BRIDGEPEER variable */
            const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER");
            if (!ast_strlen_zero(pname))
                ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */
            else
                buf[0] = 0;
        }
        ast_channel_unlock(chan);
    } else if (!strcasecmp(data, "uniqueid")) {
        locked_copy_string(chan, buf, chan->uniqueid, len);
    } else if (!strcasecmp(data, "transfercapability")) {
        locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len);
    } else if (!strcasecmp(data, "callgroup")) {
        char groupbuf[256];
        locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len);
    } else if (!strcasecmp(data, "pickupgroup")) {
        char groupbuf[256];
        locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), chan->pickupgroup), len);
    } else if (!strcasecmp(data, "amaflags")) {
        char amabuf[256];
        snprintf(amabuf,sizeof(amabuf), "%d", chan->amaflags);
        locked_copy_string(chan, buf, amabuf, len);
    } else if (!strncasecmp(data, "secure_bridge_", 14)) {
        struct ast_datastore *ds;
        ast_channel_lock(chan);
        if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
            struct ast_secure_call_store *encrypt = ds->data;
            if (!strcasecmp(data, "secure_bridge_signaling")) {
                snprintf(buf, len, "%s", encrypt->signaling ? "1" : "");
            } else if (!strcasecmp(data, "secure_bridge_media")) {
                snprintf(buf, len, "%s", encrypt->media ? "1" : "");
            }
        }
        ast_channel_unlock(chan);
    } else if (!chan->tech || !chan->tech->func_channel_read || chan->tech->func_channel_read(chan, function, data, buf, len)) {
        ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
        ret = -1;
    }

    return ret;
}
static int create_jb(struct ast_channel *chan, struct ast_frame *frr)
{
	struct ast_jb *jb = ast_channel_jb(chan);
	struct ast_jb_conf *jbconf = &jb->conf;
	const struct ast_jb_impl *jbimpl = jb->impl;
	void *jbobj;
	struct ast_channel *bridged;
	long now;
	char logfile_pathname[20 + AST_JB_IMPL_NAME_SIZE + 2*AST_CHANNEL_NAME + 1];
	char name1[AST_CHANNEL_NAME], name2[AST_CHANNEL_NAME], *tmp;
	int res;

	jbobj = jb->jbobj = jbimpl->create(jbconf, jbconf->resync_threshold);
	if (!jbobj) {
		ast_log(LOG_WARNING, "Failed to create jitterbuffer on channel '%s'\n", ast_channel_name(chan));
		return -1;
	}

	now = get_now(jb, NULL);
	res = jbimpl->put_first(jbobj, frr, now);

	/* The result of putting the first frame should not differ from OK. However, its possible
	   some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */
	if (res != AST_JB_IMPL_OK) {
		ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", ast_channel_name(chan));
		/*
		jbimpl->destroy(jbobj);
		return -1;
		*/
	}

	/* Init next */
	jb->next = jbimpl->next(jbobj);

	/* Init last format for a first time. */
	ast_format_copy(&jb->last_format, &frr->subclass.format);

	/* Create a frame log file */
	if (ast_test_flag(jbconf, AST_JB_LOG)) {
		char safe_logfile[30] = "/tmp/logfile-XXXXXX";
		int safe_fd;
		snprintf(name2, sizeof(name2), "%s", ast_channel_name(chan));
		if ((tmp = strchr(name2, '/'))) {
			*tmp = '#';
		}

		bridged = ast_bridged_channel(chan);
		/* We should always have bridged chan if a jitterbuffer is in use */
		ast_assert(bridged != NULL);

		snprintf(name1, sizeof(name1), "%s", ast_channel_name(bridged));
		if ((tmp = strchr(name1, '/'))) {
			*tmp = '#';
		}

		snprintf(logfile_pathname, sizeof(logfile_pathname),
			"/tmp/ast_%s_jb_%s--%s.log", jbimpl->name, name1, name2);
		unlink(logfile_pathname);
		safe_fd = mkstemp(safe_logfile);
		if (safe_fd < 0 || link(safe_logfile, logfile_pathname) || unlink(safe_logfile) || !(jb->logfile = fdopen(safe_fd, "w+b"))) {
			ast_log(LOG_ERROR, "Failed to create frame log file with pathname '%s': %s\n", logfile_pathname, strerror(errno));
			jb->logfile = NULL;
			if (safe_fd > -1) {
				close(safe_fd);
			}
		}

		if (res == AST_JB_IMPL_OK) {
			jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
				now, frr->ts, frr->len);
		} else {
			jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n",
				now, frr->ts, frr->len);
		}
	}

	ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl->name, ast_channel_name(chan));

	/* Free the frame if it has not been queued in the jb */
	if (res != AST_JB_IMPL_OK) {
		ast_frfree(frr);
	}

	return 0;
}
Exemple #8
0
static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
									int exact, size_t *var_len, WriteMethod **write_method)
{
	static unsigned long long_ret;
	static u_char bits_ret[2];
	static char string_ret[256];
	struct ast_channel *chan, *bridge;
	struct timeval tval;
	u_char *ret = NULL;
	int i, bit;
	struct ast_str *out = ast_str_alloca(2048);
	struct ast_channel_iterator *iter;

	if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
		return NULL;

	i = name[*length - 1] - 1;

	if (!(iter = ast_channel_iterator_all_new())) {
		return NULL;
	}

	while ((chan = ast_channel_iterator_next(iter)) && i) {
		ast_channel_unref(chan);
		i--;
	}

	iter = ast_channel_iterator_destroy(iter);

	if (chan == NULL) {
		return NULL;
	}

	*var_len = sizeof(long_ret);

	ast_channel_lock(chan);

	switch (vp->magic) {
	case ASTCHANINDEX:
		long_ret = name[*length - 1];
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANNAME:
		if (!ast_strlen_zero(ast_channel_name(chan))) {
			ast_copy_string(string_ret, ast_channel_name(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANLANGUAGE:
		if (!ast_strlen_zero(ast_channel_language(chan))) {
			ast_copy_string(string_ret, ast_channel_language(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANTYPE:
		ast_copy_string(string_ret, ast_channel_tech(chan)->type, sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMUSICCLASS:
		if (!ast_strlen_zero(ast_channel_musicclass(chan))) {
			ast_copy_string(string_ret, ast_channel_musicclass(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANBRIDGE:
		if ((bridge = ast_bridged_channel(chan)) != NULL) {
			ast_copy_string(string_ret, ast_channel_name(bridge), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANMASQ:
		if (ast_channel_masq(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masq(chan)))) {
			ast_copy_string(string_ret, ast_channel_name(ast_channel_masq(chan)), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANMASQR:
		if (ast_channel_masqr(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masqr(chan)))) {
			ast_copy_string(string_ret, ast_channel_name(ast_channel_masqr(chan)), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANWHENHANGUP:
		if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
			gettimeofday(&tval, NULL);
			long_ret = difftime(ast_channel_whentohangup(chan)->tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000;
			ret= (u_char *)&long_ret;
		}
		break;
	case ASTCHANAPP:
		if (ast_channel_appl(chan)) {
			ast_copy_string(string_ret, ast_channel_appl(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANDATA:
		if (ast_channel_data(chan)) {
			ast_copy_string(string_ret, ast_channel_data(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCONTEXT:
		ast_copy_string(string_ret, ast_channel_context(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROCONTEXT:
		ast_copy_string(string_ret, ast_channel_macrocontext(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROEXTEN:
		ast_copy_string(string_ret, ast_channel_macroexten(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROPRI:
		long_ret = ast_channel_macropriority(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANEXTEN:
		ast_copy_string(string_ret, ast_channel_exten(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANPRI:
		long_ret = ast_channel_priority(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANACCOUNTCODE:
		if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
			ast_copy_string(string_ret, ast_channel_accountcode(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANFORWARDTO:
		if (!ast_strlen_zero(ast_channel_call_forward(chan))) {
			ast_copy_string(string_ret, ast_channel_call_forward(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANUNIQUEID:
		ast_copy_string(string_ret, ast_channel_uniqueid(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANCALLGROUP:
		long_ret = ast_channel_callgroup(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANPICKUPGROUP:
		long_ret = ast_channel_pickupgroup(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANSTATE:
		long_ret = ast_channel_state(chan) & 0xffff;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANMUTED:
		long_ret = ast_channel_state(chan) & AST_STATE_MUTE ? 1 : 2;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANRINGS:
		long_ret = ast_channel_rings(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDDNID:
		if (ast_channel_dialed(chan)->number.str) {
			ast_copy_string(string_ret, ast_channel_dialed(chan)->number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDNUM:
		if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
			ast_copy_string(string_ret, ast_channel_caller(chan)->id.number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDNAME:
		if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
			ast_copy_string(string_ret, ast_channel_caller(chan)->id.name.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDANI:
		if (ast_channel_caller(chan)->ani.number.valid && ast_channel_caller(chan)->ani.number.str) {
			ast_copy_string(string_ret, ast_channel_caller(chan)->ani.number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDRDNIS:
		if (ast_channel_redirecting(chan)->from.number.valid && ast_channel_redirecting(chan)->from.number.str) {
			ast_copy_string(string_ret, ast_channel_redirecting(chan)->from.number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDPRES:
		long_ret = ast_party_id_presentation(&ast_channel_caller(chan)->id);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDANI2:
		long_ret = ast_channel_caller(chan)->ani2;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDTON:
		long_ret = ast_channel_caller(chan)->id.number.plan;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDTNS:
		long_ret = ast_channel_dialed(chan)->transit_network_select;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANAMAFLAGS:
		long_ret = ast_channel_amaflags(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANADSI:
		long_ret = ast_channel_adsicpe(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANTONEZONE:
		if (ast_channel_zone(chan)) {
			ast_copy_string(string_ret, ast_channel_zone(chan)->country, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANHANGUPCAUSE:
		long_ret = ast_channel_hangupcause(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANVARIABLES:
		if (pbx_builtin_serialize_variables(chan, &out)) {
			*var_len = ast_str_strlen(out);
			ret = (u_char *)ast_str_buffer(out);
		}
		break;
	case ASTCHANFLAGS:
		bits_ret[0] = 0;
		for (bit = 0; bit < 8; bit++)
			bits_ret[0] |= ((ast_channel_flags(chan)->flags & (1 << bit)) >> bit) << (7 - bit);
		bits_ret[1] = 0;
		for (bit = 0; bit < 8; bit++)
			bits_ret[1] |= (((ast_channel_flags(chan)->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
		*var_len = 2;
		ret = bits_ret;
		break;
	case ASTCHANTRANSFERCAP:
		long_ret = ast_channel_transfercapability(chan);
		ret = (u_char *)&long_ret;
	default:
		break;
	}

	ast_channel_unlock(chan);
	chan = ast_channel_unref(chan);

	return ret;
}
Exemple #9
0
static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
									int exact, size_t *var_len, WriteMethod **write_method)
{
	static unsigned long long_ret;
	static u_char bits_ret[2];
	static char string_ret[256];
	struct ast_channel *chan, *bridge;
	struct timeval tval;
	u_char *ret = NULL;
	int i, bit;
	struct ast_str *out = ast_str_alloca(2048);

	if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
		return NULL;

	i = name[*length - 1] - 1;
	for (chan = ast_channel_walk_locked(NULL);
		 chan && i;
		 chan = ast_channel_walk_locked(chan), i--)
		ast_channel_unlock(chan);
	if (chan == NULL)
		return NULL;
	*var_len = sizeof(long_ret);

	switch (vp->magic) {
	case ASTCHANINDEX:
		long_ret = name[*length - 1];
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANNAME:
		if (!ast_strlen_zero(chan->name)) {
			strncpy(string_ret, chan->name, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANLANGUAGE:
		if (!ast_strlen_zero(chan->language)) {
			strncpy(string_ret, chan->language, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANTYPE:
		strncpy(string_ret, chan->tech->type, sizeof(string_ret));
		string_ret[sizeof(string_ret) - 1] = '\0';
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMUSICCLASS:
		if (!ast_strlen_zero(chan->musicclass)) {
			strncpy(string_ret, chan->musicclass, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANBRIDGE:
		if ((bridge = ast_bridged_channel(chan)) != NULL) {
			strncpy(string_ret, bridge->name, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANMASQ:
		if (chan->masq && !ast_strlen_zero(chan->masq->name)) {
			strncpy(string_ret, chan->masq->name, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANMASQR:
		if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) {
			strncpy(string_ret, chan->masqr->name, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANWHENHANGUP:
		if (!ast_tvzero(chan->whentohangup)) {
			gettimeofday(&tval, NULL);
			long_ret = difftime(chan->whentohangup.tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000;
			ret= (u_char *)&long_ret;
		}
		break;
	case ASTCHANAPP:
		if (chan->appl) {
			strncpy(string_ret, chan->appl, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANDATA:
		if (chan->data) {
			strncpy(string_ret, chan->data, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCONTEXT:
		strncpy(string_ret, chan->context, sizeof(string_ret));
		string_ret[sizeof(string_ret) - 1] = '\0';
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROCONTEXT:
		strncpy(string_ret, chan->macrocontext, sizeof(string_ret));
		string_ret[sizeof(string_ret) - 1] = '\0';
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROEXTEN:
		strncpy(string_ret, chan->macroexten, sizeof(string_ret));
		string_ret[sizeof(string_ret) - 1] = '\0';
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROPRI:
		long_ret = chan->macropriority;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANEXTEN:
		strncpy(string_ret, chan->exten, sizeof(string_ret));
		string_ret[sizeof(string_ret) - 1] = '\0';
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANPRI:
		long_ret = chan->priority;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANACCOUNTCODE:
		if (!ast_strlen_zero(chan->accountcode)) {
			strncpy(string_ret, chan->accountcode, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANFORWARDTO:
		if (!ast_strlen_zero(chan->call_forward)) {
			strncpy(string_ret, chan->call_forward, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANUNIQUEID:
		strncpy(string_ret, chan->uniqueid, sizeof(string_ret));
		string_ret[sizeof(string_ret) - 1] = '\0';
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANCALLGROUP:
		long_ret = chan->callgroup;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANPICKUPGROUP:
		long_ret = chan->pickupgroup;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANSTATE:
		long_ret = chan->_state & 0xffff;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANMUTED:
		long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANRINGS:
		long_ret = chan->rings;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDDNID:
		if (chan->cid.cid_dnid) {
			strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDNUM:
		if (chan->cid.cid_num) {
			strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDNAME:
		if (chan->cid.cid_name) {
			strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDANI:
		if (chan->cid.cid_ani) {
			strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDRDNIS:
		if (chan->cid.cid_rdnis) {
			strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDPRES:
		long_ret = chan->cid.cid_pres;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDANI2:
		long_ret = chan->cid.cid_ani2;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDTON:
		long_ret = chan->cid.cid_ton;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDTNS:
		long_ret = chan->cid.cid_tns;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANAMAFLAGS:
		long_ret = chan->amaflags;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANADSI:
		long_ret = chan->adsicpe;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANTONEZONE:
		if (chan->zone) {
			strncpy(string_ret, chan->zone->country, sizeof(string_ret));
			string_ret[sizeof(string_ret) - 1] = '\0';
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANHANGUPCAUSE:
		long_ret = chan->hangupcause;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANVARIABLES:
		if (pbx_builtin_serialize_variables(chan, &out)) {
			*var_len = ast_str_strlen(out);
			ret = (u_char *)ast_str_buffer(out);
		}
		break;
	case ASTCHANFLAGS:
		bits_ret[0] = 0;
		for (bit = 0; bit < 8; bit++)
			bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit);
		bits_ret[1] = 0;
		for (bit = 0; bit < 8; bit++)
			bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
		*var_len = 2;
		ret = bits_ret;
		break;
	case ASTCHANTRANSFERCAP:
		long_ret = chan->transfercapability;
		ret = (u_char *)&long_ret;
	default:
		break;
	}
	ast_channel_unlock(chan);
	return ret;
}
Exemple #10
0
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
{
    struct timeval now;
    long elapsed_seconds = 0;
    int hour = 0, min = 0, sec = 0;
    char nf[256];
    char cgrp[256];
    char pgrp[256];
    struct ast_str *write_transpath = ast_str_alloca(256);
    struct ast_str *read_transpath = ast_str_alloca(256);

    now = ast_tvnow();
    memset(buf, 0, size);
    if (!c)
        return 0;

    if (c->cdr) {
        elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
        hour = elapsed_seconds / 3600;
        min = (elapsed_seconds % 3600) / 60;
        sec = elapsed_seconds % 60;
    }

    snprintf(buf,size,
             "Name=               %s\n"
             "Type=               %s\n"
             "UniqueID=           %s\n"
             "LinkedID=           %s\n"
             "CallerIDNum=        %s\n"
             "CallerIDName=       %s\n"
             "ConnectedLineIDNum= %s\n"
             "ConnectedLineIDName=%s\n"
             "DNIDDigits=         %s\n"
             "RDNIS=              %s\n"
             "Parkinglot=         %s\n"
             "Language=           %s\n"
             "State=              %s (%d)\n"
             "Rings=              %d\n"
             "NativeFormat=       %s\n"
             "WriteFormat=        %s\n"
             "ReadFormat=         %s\n"
             "RawWriteFormat=     %s\n"
             "RawReadFormat=      %s\n"
             "WriteTranscode=     %s %s\n"
             "ReadTranscode=      %s %s\n"
             "1stFileDescriptor=  %d\n"
             "Framesin=           %d %s\n"
             "Framesout=          %d %s\n"
             "TimetoHangup=       %ld\n"
             "ElapsedTime=        %dh%dm%ds\n"
             "DirectBridge=       %s\n"
             "IndirectBridge=     %s\n"
             "Context=            %s\n"
             "Extension=          %s\n"
             "Priority=           %d\n"
             "CallGroup=          %s\n"
             "PickupGroup=        %s\n"
             "Application=        %s\n"
             "Data=               %s\n"
             "Blocking_in=        %s\n",
             c->name,
             c->tech->type,
             c->uniqueid,
             c->linkedid,
             S_COR(c->caller.id.number.valid, c->caller.id.number.str, "(N/A)"),
             S_COR(c->caller.id.name.valid, c->caller.id.name.str, "(N/A)"),
             S_COR(c->connected.id.number.valid, c->connected.id.number.str, "(N/A)"),
             S_COR(c->connected.id.name.valid, c->connected.id.name.str, "(N/A)"),
             S_OR(c->dialed.number.str, "(N/A)"),
             S_COR(c->redirecting.from.number.valid, c->redirecting.from.number.str, "(N/A)"),
             c->parkinglot,
             c->language,
             ast_state2str(c->_state),
             c->_state,
             c->rings,
             ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
             ast_getformatname(&c->writeformat),
             ast_getformatname(&c->readformat),
             ast_getformatname(&c->rawwriteformat),
             ast_getformatname(&c->rawreadformat),
             c->writetrans ? "Yes" : "No",
             ast_translate_path_to_str(c->writetrans, &write_transpath),
             c->readtrans ? "Yes" : "No",
             ast_translate_path_to_str(c->readtrans, &read_transpath),
             c->fds[0],
             c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
             c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
             (long)c->whentohangup.tv_sec,
             hour,
             min,
             sec,
             c->_bridge ? c->_bridge->name : "<none>",
             ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
             c->context,
             c->exten,
             c->priority,
             ast_print_group(cgrp, sizeof(cgrp), c->callgroup),
             ast_print_group(pgrp, sizeof(pgrp), c->pickupgroup),
             c->appl ? c->appl : "(N/A)",
             c->data ? S_OR(c->data, "(Empty)") : "(None)",
             (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));

    return 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;
}
Exemple #12
0
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
		const char *userdefevname, const char *extra, struct ast_channel *peer2)
{
	struct timeval eventtime;
	struct ast_event *ev;
	const char *peername = "";
	struct ast_channel *peer;
	char *linkedid = ast_strdupa(ast_channel_linkedid(chan));

	/* Make sure a reload is not occurring while we're checking to see if this
	 * is an event that we care about.  We could lose an important event in this
	 * process otherwise. */
	ast_mutex_lock(&reload_lock);

	/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
	 * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
	if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
		if (ast_cel_linkedid_ref(linkedid)) {
			ast_mutex_unlock(&reload_lock);
			return -1;
		}
	}

	if (!cel_enabled || !ast_cel_track_event(event_type)) {
		ast_mutex_unlock(&reload_lock);
		return 0;
	}

	if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
		char *app;
		if (!(app = ao2_find(appset, (char *) ast_channel_appl(chan), OBJ_POINTER))) {
			ast_mutex_unlock(&reload_lock);
			return 0;
		}
		ao2_ref(app, -1);
	}

	ast_mutex_unlock(&reload_lock);

	ast_channel_lock(chan);
	peer = ast_bridged_channel(chan);
	if (peer) {
		ast_channel_ref(peer);
	}
	ast_channel_unlock(chan);

	if (peer) {
		ast_channel_lock(peer);
		peername = ast_strdupa(ast_channel_name(peer));
		ast_channel_unlock(peer);
	} else if (peer2) {
		ast_channel_lock(peer2);
		peername = ast_strdupa(ast_channel_name(peer2));
		ast_channel_unlock(peer2);
	}

	if (!userdefevname) {
		userdefevname = "";
	}

	if (!extra) {
		extra = "";
	}

	eventtime = ast_tvnow();

	ast_channel_lock(chan);

	ev = ast_event_new(AST_EVENT_CEL,
		AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
		AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
		AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
		AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
		AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
		AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
		AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
		AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
			S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
		AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
			S_OR(ast_channel_dialed(chan)->number.str, ""),
		AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
		AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
		AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
		AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
		AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
		AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
		AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
		AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
		AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
		AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
		AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
		AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
		AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
		AST_EVENT_IE_END);

	ast_channel_unlock(chan);

	if (peer) {
		peer = ast_channel_unref(peer);
	}

	if (ev && ast_event_queue(ev)) {
		ast_event_destroy(ev);
		return -1;
	}

	return 0;
}
Exemple #13
0
/* Find channel matching given pattern and state, skipping our own channel.
 * Returns locked channel, which has to be unlocked using ast_mutex_unlock().
 * Returns NULL when no matching channel is found.
 */
static struct ast_channel *find_matching_channel(struct ast_channel *chan,
	void *pattern, int chanstate)
{
	struct ast_channel *cur;
	char *pat = "";
	char *next_pat = NULL;
	char *option = "";
	struct ast_channel *bridged;

	/* copy original pattern or use empty pattern if no pattern has been given*/
	if (pattern) {
		pat = alloca(strlen(pattern) + 1);
		strcpy(pat, pattern);
	}
	for (option = pat; *option; option++) {
		if (*option == '|') {
			*option = '\0';
			option++;
			break;
		}
	}
	ast_verbose(VERBOSE_PREFIX_4 
		"find_matching_channel: pattern='%s' option='%s' state=%d\n",
		(char *)pat, option, chanstate);

	/* match on bridged channel name */
	if (!strcmp("B", option)) {
		/* Iterate over each part of the pattern */
		while (pat) {
			/* find pattern for next iteration, 
			 * terminate current pattern */
			for (next_pat = pat; 
				*next_pat && *next_pat != '&'; next_pat++);
			if (*next_pat == '&') {
				*next_pat = 0;
				next_pat++;
			} else
				next_pat = NULL;
			/* Iterate over all channels */
			cur = ast_channel_walk_locked(NULL);
			while (cur) {
				bridged = ast_bridged_channel(cur);
				if (bridged) {
					ast_verbose(VERBOSE_PREFIX_4 
						"find_matching_channel: trying channel='%s' bridged='%s' "
						"state=%d pattern='%s'\n",
						cur->name, bridged->name, cur->_state, pat);
					if ((cur != chan) && (bridged != chan) &&
						(cur->_state == chanstate) &&
						!strncmp(pat, bridged->name, strlen(pat))) {
						ast_verbose(VERBOSE_PREFIX_4
								"find_matching_channel: "
								"found channel='%s' bridged='%s'\n",
								cur->name, bridged->name);
						return(cur);
					}
				}
				ast_mutex_unlock(&cur->lock);
				cur = ast_channel_walk_locked(cur);
			}
			pat = next_pat;
		}
	} else {
		/* Iterate over each part of the pattern */
		while (pat) {
			/* find pattern for next iteration, 
			 * terminate current pattern */
			for (next_pat = pat; 
				*next_pat && *next_pat != '&'; next_pat++);
			if (*next_pat == '&') {
				*next_pat = 0;
				next_pat++;
			} else
				next_pat = NULL;
			/* Iterate over all channels */
			cur = ast_channel_walk_locked(NULL);
			while (cur) {
				ast_verbose(VERBOSE_PREFIX_4 
					"find_matching_channel: trying channel='%s' "
					"state=%d pattern='%s'\n",
					cur->name, cur->_state, pat);
				if ((cur != chan) && 
					(cur->_state == chanstate) &&
					!strncmp(pat, cur->name, strlen(pat))) {
					ast_verbose(VERBOSE_PREFIX_4
							"find_matching_channel: "
							"found channel='%s'\n",
							cur->name);
					return(cur);
				}
				ast_mutex_unlock(&cur->lock);
				cur = ast_channel_walk_locked(cur);
			}
			pat = next_pat;
		}
	}
	return(NULL);
}
Exemple #14
0
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 exitcontext[AST_MAX_CONTEXT] = "";
	signed char zero_volume = 0;
	int waitms;
	int res;
	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(ast_channel_macrocontext(chan))) {
			ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
		} else {
			ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
		}
		ast_channel_unlock(chan);
	}

	if (ast_channel_state(chan) != AST_STATE_UP)
		ast_answer(chan);

	ast_set_flag(ast_channel_flags(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", ast_channel_language(chan));
			if (!res)
				res = ast_waitstream(chan, "");
			else if (res < 0) {
				ast_clear_flag(ast_channel_flags(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) {
			res = -1;
			goto exit;
		}

		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			iter = ast_channel_iterator_destroy(iter);
			ast_clear_flag(ast_channel_flags(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)) {
				iter = ast_channel_iterator_destroy(iter);
				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;

			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(ast_channel_flags(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, ast_channel_name(autochan->chan), sizeof(ext) - 1);
				if ((end = strchr(ext, '-'))) {
					*end++ = ':';
					*end = '\0';
				}

				ext[0] = ':';

				if (strcasestr(buffer, ext)) {
					ienf = 1;
				}
			}

			if (!ienf) {
				continue;
			}

			if (!ast_test_flag(flags, OPTION_QUIET)) {
				char peer_name[AST_NAME_STRLEN + 5];
				char *ptr, *s;

				strcpy(peer_name, "spy-");
				strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
				if ((ptr = strchr(peer_name, '/'))) {
					*ptr++ = '\0';
					for (s = peer_name; s < ptr; s++) {
						*s = tolower(*s);
					}
					if ((s = strchr(ptr, '-'))) {
						*s = '\0';
					}
				}

				if (ast_test_flag(flags, OPTION_NAME)) {
					const char *local_context = S_OR(name_context, "default");
					const char *local_mailbox = S_OR(mailbox, ptr);
					if (local_mailbox) {
						res = ast_app_sayname(chan, local_mailbox, local_context);
					} else {
						res = -1;
					}
				}
				if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
					int num;
					if (!ast_test_flag(flags, OPTION_NOTECH)) {
						if (ast_fileexists(peer_name, NULL, NULL) > 0) {
							res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
							if (!res) {
								res = ast_waitstream(chan, "");
							}
							if (res) {
								ast_autochan_destroy(autochan);
								break;
							}
						} else {
							res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan));
						}
					}
					if (ptr && (num = atoi(ptr))) {
						ast_say_digits(chan, num, "", ast_channel_language(chan));
					}
				}
			}

			res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
			num_spyed_upon++;

			if (res == -1) {
				ast_autochan_destroy(autochan);
				iter = ast_channel_iterator_destroy(iter);
				goto exit;
			} else if (res == -2) {
				res = 0;
				ast_autochan_destroy(autochan);
				iter = ast_channel_iterator_destroy(iter);
				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)) {
				ast_autochan_destroy(autochan);
				iter = ast_channel_iterator_destroy(iter);
				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(ast_channel_flags(chan), AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	return res;
}
Exemple #15
0
static void *mixmonitor_thread(void *obj) 
{
	struct mixmonitor *mixmonitor = obj;
	struct ast_filestream *fs = NULL;
	unsigned int oflags;
	char *ext;
	int errflag = 0;

	if (option_verbose > 1)
		ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name);
	
	ast_audiohook_lock(&mixmonitor->audiohook);

	while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		struct ast_frame *fr = NULL;
		
		ast_audiohook_trigger_wait(&mixmonitor->audiohook);
		
		if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
			break;
		
		if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
			continue;

		ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
			/* Initialize the file if not already done so */
			if (!fs && !errflag) {
				oflags = O_CREAT | O_WRONLY;
				oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
				
				if ((ext = strrchr(mixmonitor->filename, '.')))
					*(ext++) = '\0';
				else
					ext = "raw";
				
				if (!(fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) {
					ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
					errflag = 1;
				}
			}

			/* Write out the frame */
			if (fs)
				ast_writestream(fs, fr);
		} else {
			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
		}

		/* All done! free it. */
		ast_frame_free(fr, 0);
	}

	ast_audiohook_detach(&mixmonitor->audiohook);
	ast_audiohook_unlock(&mixmonitor->audiohook);
	ast_audiohook_destroy(&mixmonitor->audiohook);
	
	if (option_verbose > 1)
		ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);

	if (fs)
		ast_closestream(fs);

	if (mixmonitor->post_process) {
		if (option_verbose > 2)
			ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
		ast_safe_system(mixmonitor->post_process);
	}

	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
	if (!mixmonitor->mixmonitor_ds->destruction_ok) {
		ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
	}
	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
	ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
	ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
	ast_free(mixmonitor->mixmonitor_ds);
	free(mixmonitor);

	return NULL;
}
Exemple #16
0
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
{
	struct timeval now;
	long elapsed_seconds = 0;
	int hour = 0, min = 0, sec = 0;
	char nf[256];
	char cgrp[256];
	char pgrp[256];
	struct ast_str *write_transpath = ast_str_alloca(256);
	struct ast_str *read_transpath = ast_str_alloca(256);

	now = ast_tvnow();
	memset(buf, 0, size);
	if (!c)
		return 0;

	if (ast_channel_cdr(c)) {
		elapsed_seconds = now.tv_sec - ast_channel_cdr(c)->start.tv_sec;
		hour = elapsed_seconds / 3600;
		min = (elapsed_seconds % 3600) / 60;
		sec = elapsed_seconds % 60;
	}

	snprintf(buf,size,
		"Name=               %s\n"
		"Type=               %s\n"
		"UniqueID=           %s\n"
		"LinkedID=           %s\n"
		"CallerIDNum=        %s\n"
		"CallerIDName=       %s\n"
		"ConnectedLineIDNum= %s\n"
		"ConnectedLineIDName=%s\n"
		"DNIDDigits=         %s\n"
		"RDNIS=              %s\n"
		"Parkinglot=         %s\n"
		"Language=           %s\n"
		"State=              %s (%d)\n"
		"Rings=              %d\n"
		"NativeFormat=       %s\n"
		"WriteFormat=        %s\n"
		"ReadFormat=         %s\n"
		"RawWriteFormat=     %s\n"
		"RawReadFormat=      %s\n"
		"WriteTranscode=     %s %s\n"
		"ReadTranscode=      %s %s\n"
		"1stFileDescriptor=  %d\n"
		"Framesin=           %d %s\n"
		"Framesout=          %d %s\n"
		"TimetoHangup=       %ld\n"
		"ElapsedTime=        %dh%dm%ds\n"
		"DirectBridge=       %s\n"
		"IndirectBridge=     %s\n"
		"Context=            %s\n"
		"Extension=          %s\n"
		"Priority=           %d\n"
		"CallGroup=          %s\n"
		"PickupGroup=        %s\n"
		"Application=        %s\n"
		"Data=               %s\n"
		"Blocking_in=        %s\n",
		ast_channel_name(c),
		ast_channel_tech(c)->type,
		ast_channel_uniqueid(c),
		ast_channel_linkedid(c),
		S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"),
		S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"),
		S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"),
		S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"),
		S_OR(ast_channel_dialed(c)->number.str, "(N/A)"),
		S_COR(ast_channel_redirecting(c)->from.number.valid, ast_channel_redirecting(c)->from.number.str, "(N/A)"),
		ast_channel_parkinglot(c),
		ast_channel_language(c),
		ast_state2str(ast_channel_state(c)),
		ast_channel_state(c),
		ast_channel_rings(c),
		ast_getformatname_multiple(nf, sizeof(nf), ast_channel_nativeformats(c)),
		ast_getformatname(ast_channel_writeformat(c)),
		ast_getformatname(ast_channel_readformat(c)),
		ast_getformatname(ast_channel_rawwriteformat(c)),
		ast_getformatname(ast_channel_rawreadformat(c)),
		ast_channel_writetrans(c) ? "Yes" : "No",
		ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath),
		ast_channel_readtrans(c) ? "Yes" : "No",
		ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath),
		ast_channel_fd(c, 0),
		ast_channel_fin(c) & ~DEBUGCHAN_FLAG, (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
		ast_channel_fout(c) & ~DEBUGCHAN_FLAG, (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
		(long)ast_channel_whentohangup(c)->tv_sec,
		hour,
		min,
		sec,
		ast_channel_internal_bridged_channel(c) ? ast_channel_name(ast_channel_internal_bridged_channel(c)) : "<none>",
		ast_bridged_channel(c) ? ast_channel_name(ast_bridged_channel(c)) : "<none>",
		ast_channel_context(c),
		ast_channel_exten(c),
		ast_channel_priority(c),
		ast_print_group(cgrp, sizeof(cgrp), ast_channel_callgroup(c)),
		ast_print_group(pgrp, sizeof(pgrp), ast_channel_pickupgroup(c)),
		ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)",
		ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)",
		(ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"));

	return 0;
}
Exemple #17
0
static void *mixmonitor_thread(void *obj) 
{
	struct mixmonitor *mixmonitor = obj;
	struct ast_filestream **fs = NULL;
	unsigned int oflags;
	char *ext;
	int errflag = 0;

	ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);

	fs = &mixmonitor->mixmonitor_ds->fs;

	/* The audiohook must enter and exit the loop locked */
	ast_audiohook_lock(&mixmonitor->audiohook);
	while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
		struct ast_frame *fr = NULL;

		ast_audiohook_trigger_wait(&mixmonitor->audiohook);

		if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
			break;

		if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
			continue;

		/* audiohook lock is not required for the next block.
		 * Unlock it, but remember to lock it before looping or exiting */
		ast_audiohook_unlock(&mixmonitor->audiohook);

		ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
			/* Initialize the file if not already done so */
			if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
				oflags = O_CREAT | O_WRONLY;
				oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;

				if ((ext = strrchr(mixmonitor->filename, '.')))
					*(ext++) = '\0';
				else
					ext = "raw";

				if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) {
					ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
					errflag = 1;
				}
			}

			/* Write out the frame(s) */
			if (*fs) {
				struct ast_frame *cur;

				for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
					ast_writestream(*fs, cur);
				}
			}
		}
		ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);

		/* All done! free it. */
		ast_frame_free(fr, 0);
		ast_audiohook_lock(&mixmonitor->audiohook);
	}

	ast_audiohook_unlock(&mixmonitor->audiohook);

	/* Datastore cleanup.  close the filestream and wait for ds destruction */
	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
	mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
	if (!mixmonitor->mixmonitor_ds->destruction_ok) {
		ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
	}
	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);

	/* kill the audiohook */
	destroy_monitor_audiohook(mixmonitor);

	if (mixmonitor->post_process) {
		ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
		ast_safe_system(mixmonitor->post_process);
	}

	ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
	mixmonitor_free(mixmonitor);
	return NULL;
}
Exemple #18
0
static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
	int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
	char *exitcontext)
{
	struct chanspy_translation_helper csth;
	int running = 0, res, x = 0;
	char inp[24] = {0};
	char *name;
	struct ast_frame *f;
	struct ast_silence_generator *silgen = NULL;
	struct ast_autochan *spyee_bridge_autochan = NULL;
	const char *spyer_name;
	struct ast_channel *chans[] = { chan, spyee_autochan->chan };

	ast_channel_lock(chan);
	spyer_name = ast_strdupa(chan->name);
	ast_channel_unlock(chan);

	/* We now hold the channel lock on spyee */

	if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
		return 0;
	}

	ast_channel_lock(spyee_autochan->chan);
	name = ast_strdupa(spyee_autochan->chan->name);
	ast_channel_unlock(spyee_autochan->chan);

	ast_verb(2, "Spying on channel %s\n", name);
	ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
			"SpyerChannel: %s\r\n"
			"SpyeeChannel: %s\r\n",
			spyer_name, name);

	memset(&csth, 0, sizeof(csth));
	ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);

	ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");

	if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
		ast_audiohook_destroy(&csth.spy_audiohook);
		return 0;
	}

	ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
	ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
	if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
		ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
	}
	if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
		ast_channel_lock(spyee_bridge_autochan->chan);
		if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
			ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
		}
		ast_channel_unlock(spyee_bridge_autochan->chan);
	}

	ast_channel_lock(chan);
	ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	csth.volfactor = *volfactor;

	if (csth.volfactor) {
		csth.spy_audiohook.options.read_volume = csth.volfactor;
		csth.spy_audiohook.options.write_volume = csth.volfactor;
	}

	csth.fd = fd;

	if (ast_test_flag(flags, OPTION_PRIVATE))
		silgen = ast_channel_start_silence_generator(chan);
	else
		ast_activate_generator(chan, &spygen, &csth);

	/* We can no longer rely on 'spyee' being an actual channel;
	   it can be hung up and freed out from under us. However, the
	   channel destructor will put NULL into our csth.spy.chan
	   field when that happens, so that is our signal that the spyee
	   channel has gone away.
	*/

	/* 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 a frame
	   has arrived, since the spied-on channel could have gone away while
	   we were waiting
	*/
	while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_lock(&csth.bridge_whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
			ast_frfree(f);
			continue;
		} else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
			ast_audiohook_lock(&csth.whisper_audiohook);
			ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
			ast_audiohook_unlock(&csth.whisper_audiohook);
			ast_frfree(f);
			continue;
		}
		
		res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
		ast_frfree(f);
		if (!res)
			continue;

		if (x == sizeof(inp))
			x = 0;

		if (res < 0) {
			running = -1;
			break;
		}

		if (ast_test_flag(flags, OPTION_EXIT)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
				ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
				pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
				running = -2;
				break;
			} else {
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		} else if (res >= '0' && res <= '9') {
			if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
				change_spy_mode(res, flags);
			} else {
				inp[x++] = res;
			}
		}

		if (res == user_options->cycle) {
			running = 0;
			break;
		} else if (res == user_options->exit) {
			running = -2;
			break;
		} else if (res == user_options->volume) {
			if (!ast_strlen_zero(inp)) {
				running = atoi(inp);
				break;
			}

			(*volfactor)++;
			if (*volfactor > 4)
				*volfactor = -4;
			ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);

			csth.volfactor = *volfactor;
			csth.spy_audiohook.options.read_volume = csth.volfactor;
			csth.spy_audiohook.options.write_volume = csth.volfactor;
		}
	}

	if (ast_test_flag(flags, OPTION_PRIVATE))
		ast_channel_stop_silence_generator(chan, silgen);
	else
		ast_deactivate_generator(chan);

	ast_channel_lock(chan);
	ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
	ast_channel_unlock(chan);

	ast_audiohook_lock(&csth.whisper_audiohook);
	ast_audiohook_detach(&csth.whisper_audiohook);
	ast_audiohook_unlock(&csth.whisper_audiohook);
	ast_audiohook_destroy(&csth.whisper_audiohook);
	
	ast_audiohook_lock(&csth.bridge_whisper_audiohook);
	ast_audiohook_detach(&csth.bridge_whisper_audiohook);
	ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
	ast_audiohook_destroy(&csth.bridge_whisper_audiohook);

	ast_audiohook_lock(&csth.spy_audiohook);
	ast_audiohook_detach(&csth.spy_audiohook);
	ast_audiohook_unlock(&csth.spy_audiohook);
	ast_audiohook_destroy(&csth.spy_audiohook);

	if (spyee_bridge_autochan) {
		ast_autochan_destroy(spyee_bridge_autochan);
	}

	ast_verb(2, "Done Spying on channel %s\n", name);
	ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);

	return running;
}
Exemple #19
0
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;
}