예제 #1
0
static int container_test1_helper(struct ast_format_cap *cap1, struct ast_format_cap *cap2, struct ast_test *test)
{

	int res = AST_TEST_PASS;
	struct ast_format_cap *cap_joint = NULL;
	struct ast_format tmpformat;

	if (ast_format_attr_reg_interface(&test_interface)) {
		ast_test_status_update(test, "test_interface failed to register.\n");
		ast_format_cap_destroy(cap1);
		ast_format_cap_destroy(cap2);
		return AST_TEST_FAIL;
	}

	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_G722, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_H263, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0));
	ast_format_cap_add(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ,
			AST_FORMAT_ATTR_END));

	/* Test is compatible */
	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) ||
		!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 1.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Test things that are not compatible */
	if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX, 0)) ||
		ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_SPEEX16, 0)) ||
		ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_H261, 0))) {
		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 2.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Test compatiblity with format with attributes. */
	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 3.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	if (!ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 4.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	if (ast_format_cap_iscompatible(cap1, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ, /* 48khz was not compatible, so this should fail iscompatible check */
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap1 failed to properly detect compatibility test 5.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Lets start testing the functions that compare ast_format_cap objects.
	 * Genreate the cap2 object to contain some similar formats as cap1
	 * and some different formats as well. */
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_H261, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_T140, 0));
	ast_format_cap_add(cap2, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_12KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_32KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ,
			AST_FORMAT_ATTR_END));


	/* find joint formats between cap1 and cap2 */
	cap_joint = ast_format_cap_joint(cap1, cap2);

	if (!cap_joint) {
		ast_test_status_update(test, "failed to create joint capabilities correctly.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* determine if cap_joint is what we think it should be */
	if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* make sure joint cap does not have formats that should not be there */
	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_SIREN7, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_TESTLAW, 1,
			TEST_ATTR_KEY_STRING, "testing caps hooray",
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_8KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_16KHZ,
			TEST_ATTR_KEY_SAMP_RATE, TEST_ATTR_VAL_SAMP_48KHZ,
			AST_FORMAT_ATTR_END))) {

		ast_test_status_update(test, "ast cap_joint failed to properly detect compatibility test 1.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* Lets test removing a capability */
	if (ast_format_cap_remove(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
		ast_test_status_update(test, "ast_format_cap_remove failed. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* Lets make sure what we just removed does not still exist */
	if (ast_format_cap_iscompatible(cap_joint, &tmpformat)) {
		ast_test_status_update(test, "ast_format_cap_remove failed 2. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* Lets test removing a capability by id.*/
	if (ast_format_cap_remove_byid(cap_joint, AST_FORMAT_GSM)) {
		ast_test_status_update(test, "ast_format_cap_remove failed 3. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* Lets make sure what we just removed does not still exist */
	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0))) {
		ast_test_status_update(test, "ast_format_cap_remove failed 4. \n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* lets test getting joint formats by type */
	ast_format_cap_destroy(cap_joint);
	if (!(cap_joint = ast_format_cap_get_type(cap1, AST_FORMAT_TYPE_VIDEO))) {
		ast_test_status_update(test, "ast_format_cap_get_type failed.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* lets make sure our joint capability structure has what we expect */
	if (!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H264, 0)) ||
		!ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_H263, 0))) {
		ast_test_status_update(test, "get_type failed 2.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	/* now make sure joint does not have anything but video */
	if (ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ALAW, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_ULAW, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_GSM, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_JPEG, 0)) ||
		ast_format_cap_iscompatible(cap_joint, ast_format_set(&tmpformat, AST_FORMAT_T140, 0))) {
		ast_test_status_update(test, "get_type failed 3.\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* now lets remove everythign from cap_joint */
	ast_format_cap_remove_all(cap_joint);
	if (!ast_format_cap_is_empty(cap_joint)) {
		ast_test_status_update(test, "failed to remove all\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

	/* now lets add all by type */
	ast_format_cap_add_all_by_type(cap_joint, AST_FORMAT_TYPE_AUDIO);
	if (ast_format_cap_is_empty(cap_joint)) {
			ast_test_status_update(test, "failed to add all by type AUDIO\n");
			res = AST_TEST_FAIL;
	}
	ast_format_cap_iter_start(cap_joint);
	while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
		if (AST_FORMAT_GET_TYPE(tmpformat.id) != AST_FORMAT_TYPE_AUDIO) {
			ast_test_status_update(test, "failed to add all by type AUDIO\n");
			res = AST_TEST_FAIL;
			ast_format_cap_iter_end(cap_joint);
			goto test3_cleanup;
		}
	}
	ast_format_cap_iter_end(cap_joint);

	/* test append */
	ast_format_cap_append(cap_joint, cap1);
	ast_format_cap_iter_start(cap1);
	while (!(ast_format_cap_iter_next(cap1, &tmpformat))) {
		if (!ast_format_cap_iscompatible(cap_joint, &tmpformat)) {
			ast_test_status_update(test, "failed to append format capabilities.\n");
			res = AST_TEST_FAIL;
			ast_format_cap_iter_end(cap1);
			goto test3_cleanup;
		}
	}
	ast_format_cap_iter_end(cap1);

	/* test copy */
	cap1 = ast_format_cap_destroy(cap1);
	cap1 = ast_format_cap_dup(cap_joint);
	if (!ast_format_cap_identical(cap_joint, cap1)) {
			ast_test_status_update(test, "failed to copy capabilities\n");
			res = AST_TEST_FAIL;
			goto test3_cleanup;
	}

	/* test remove by type */
	ast_format_cap_remove_bytype(cap_joint, AST_FORMAT_TYPE_AUDIO);
	if (ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_AUDIO)) {
		ast_test_status_update(test, "failed to remove all by type audio\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	if (!ast_format_cap_has_type(cap_joint, AST_FORMAT_TYPE_TEXT)) { /* it should still have text */
		ast_test_status_update(test, "failed to remove all by type audio\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}
	ast_format_cap_iter_start(cap_joint);
	while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
		if (AST_FORMAT_GET_TYPE(tmpformat.id) == AST_FORMAT_TYPE_AUDIO) {
			ast_test_status_update(test, "failed to remove all by type audio\n");
			res = AST_TEST_FAIL;
			ast_format_cap_iter_end(cap_joint);
			goto test3_cleanup;
		}
	}
	ast_format_cap_iter_end(cap_joint);

	/* test add all */
	ast_format_cap_remove_all(cap_joint);
	ast_format_cap_add_all(cap_joint);
	{
		int video = 0, audio = 0, text = 0, image = 0;
		ast_format_cap_iter_start(cap_joint);
		while (!(ast_format_cap_iter_next(cap_joint, &tmpformat))) {
			switch (AST_FORMAT_GET_TYPE(tmpformat.id)) {
			case AST_FORMAT_TYPE_AUDIO:
				audio++;
				break;
			case AST_FORMAT_TYPE_VIDEO:
				video++;
				break;
			case AST_FORMAT_TYPE_TEXT:
				text++;
				break;
			case AST_FORMAT_TYPE_IMAGE:
				image++;
				break;
			}
		}
		ast_format_cap_iter_end(cap_joint);
		if (!video || !audio || !text || !image) {
			ast_test_status_update(test, "failed to add all\n");
			res = AST_TEST_FAIL;
			goto test3_cleanup;
		}
	}

	/* test copy2 */
	ast_format_cap_copy(cap2, cap_joint);
	if (!ast_format_cap_identical(cap2, cap_joint)) {
		ast_test_status_update(test, "ast_format_cap_copy failed\n");
		res = AST_TEST_FAIL;
		goto test3_cleanup;
	}

test3_cleanup:
	ast_format_cap_destroy(cap1);
	ast_format_cap_destroy(cap2);
	ast_format_cap_destroy(cap_joint);

	/* unregister interface */
	if (ast_format_attr_unreg_interface(&test_interface)) {
		ast_test_status_update(test, "test_interface failed to unregister.\n");
		res = AST_TEST_FAIL;
	}

	return res;
}
예제 #2
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;
}
예제 #3
0
static int func_channel_read(struct ast_channel *chan, const char *function,
			     char *data, char *buf, size_t len)
{
	int ret = 0;
	struct ast_format_cap *tmpcap;

	if (!chan) {
		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
		return -1;
	}

	if (!strcasecmp(data, "audionativeformat")) {
		char tmp[512];

		if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), 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")) {
		char tmp[512];

		if ((tmpcap = ast_format_cap_get_type(ast_channel_nativeformats(chan), 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(ast_channel_readformat(chan)), len);
	} else if (!strcasecmp(data, "audiowriteformat")) {
		ast_copy_string(buf, ast_getformatname(ast_channel_writeformat(chan)), 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") && ast_channel_zone(chan)) {
		locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len);
	} else if (!strcasecmp(data, "dtmf_features")) {
		if (ast_bridge_features_ds_get_string(chan, buf, len)) {
			buf[0] = '\0';
		}
	} else if (!strcasecmp(data, "language"))
		locked_copy_string(chan, buf, ast_channel_language(chan), len);
	else if (!strcasecmp(data, "musicclass"))
		locked_copy_string(chan, buf, ast_channel_musicclass(chan), len);
	else if (!strcasecmp(data, "name")) {
		locked_copy_string(chan, buf, ast_channel_name(chan), len);
	} else if (!strcasecmp(data, "parkinglot"))
		locked_copy_string(chan, buf, ast_channel_parkinglot(chan), len);
	else if (!strcasecmp(data, "state"))
		locked_copy_string(chan, buf, ast_state2str(ast_channel_state(chan)), len);
	else if (!strcasecmp(data, "channeltype"))
		locked_copy_string(chan, buf, ast_channel_tech(chan)->type, len);
	else if (!strcasecmp(data, "accountcode"))
		locked_copy_string(chan, buf, ast_channel_accountcode(chan), 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, ast_channel_peeraccount(chan), len);
	else if (!strcasecmp(data, "hangupsource"))
		locked_copy_string(chan, buf, ast_channel_hangupsource(chan), len);
	else if (!strcasecmp(data, "appname") && ast_channel_appl(chan))
		locked_copy_string(chan, buf, ast_channel_appl(chan), len);
	else if (!strcasecmp(data, "appdata") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_data(chan), len);
	else if (!strcasecmp(data, "exten") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_exten(chan), len);
	else if (!strcasecmp(data, "context") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_context(chan), len);
	else if (!strcasecmp(data, "userfield") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_userfield(chan), len);
	else if (!strcasecmp(data, "channame") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_name(chan), len);
	else if (!strcasecmp(data, "linkedid")) {
		ast_channel_lock(chan);
		if (ast_strlen_zero(ast_channel_linkedid(chan))) {
			/* fall back on the channel's uniqueid if linkedid is unset */
			ast_copy_string(buf, ast_channel_uniqueid(chan), len);
		}
		else {
			ast_copy_string(buf, ast_channel_linkedid(chan), len);
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "peer")) {
		RAII_VAR(struct ast_channel *, p, NULL, ast_channel_cleanup);

		ast_channel_lock(chan);
		p = ast_channel_bridge_peer(chan);
		if (p || ast_channel_tech(chan)) /* dummy channel? if so, we hid the peer name in the language */
			ast_copy_string(buf, (p ? ast_channel_name(p) : ""), 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, ast_channel_uniqueid(chan), len);
	} else if (!strcasecmp(data, "transfercapability")) {
		locked_copy_string(chan, buf, transfercapability_table[ast_channel_transfercapability(chan) & 0x1f], len);
	} else if (!strcasecmp(data, "callgroup")) {
		char groupbuf[256];

		locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_callgroup(chan)), len);
	} else if (!strcasecmp(data, "pickupgroup")) {
		char groupbuf[256];

		locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_pickupgroup(chan)), len);
	} else if (!strcasecmp(data, "namedcallgroup")) {
		struct ast_str *tmp_str = ast_str_alloca(1024);

		locked_copy_string(chan, buf,  ast_print_namedgroups(&tmp_str, ast_channel_named_callgroups(chan)), len);
	} else if (!strcasecmp(data, "namedpickupgroup")) {
		struct ast_str *tmp_str = ast_str_alloca(1024);

		locked_copy_string(chan, buf,  ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len);
	} else if (!strcasecmp(data, "after_bridge_goto")) {
		ast_bridge_read_after_goto(chan, buf, len);
	} else if (!strcasecmp(data, "amaflags")) {
		ast_channel_lock(chan);
		snprintf(buf, len, "%d", ast_channel_amaflags(chan));
		ast_channel_unlock(chan);
	} 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 (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
		ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
		ret = -1;
	}

	return ret;
}