예제 #1
0
파일: app_call.c 프로젝트: irontec/isaac
/**
 * @brief Hangup action entry point
 *
 * Hangup action will Hangup the first channel generated using
 * CALL action using the manager application Hangup. The hangup
 * events will still be parsed by @ref call_state function, unregistering
 * the pending filters
 *
 * @param sess Session rnuning this application
 * @param app The application structure
 * @param args Hangup action args "ActionID"
 * @return 0 if the call is found, -1 otherwise
 */
int
hangup_exec(session_t *sess, app_t *app, const char *args)
{
    struct app_call_info *info;
    char actionid[ACTIONID_LEN];

    // This can only be done after authentication
    if (!session_test_flag(sess, SESS_FLAG_AUTHENTICATED)) {
        return NOT_AUTHENTICATED;
    }

    // Get Hangup parameteres
    if (sscanf(args, "%s", actionid) != 1) {
        return INVALID_ARGUMENTS;
    }

    // Try to find the action info of the given actionid
    if ((info = get_call_info_from_id(sess, actionid))) { 
        if (!isaac_strlen_zero(info->ochannel)) {
            ami_message_t msg;
            memset(&msg, 0, sizeof(ami_message_t));
            message_add_header(&msg, "Action: Hangup");
            message_add_header(&msg, "Channel: %s", info->ochannel);
            manager_write_message(manager, &msg);
            session_write(sess, "HANGUPOK\r\n");
        } else {
            session_write(sess, "HANGUPFAILED CHANNEL NOT FOUND\r\n");
        }
    } else {
        session_write(sess, "HANGUPFAILED ID NOT FOUND\r\n");
        return -1;
    }
    return 0;
}
예제 #2
0
파일: app_call.c 프로젝트: irontec/isaac
/**
 * @brief DTMF action entry point
 *
 * DTMF action will send a DTMF code to a second channel generated using
 * CALL action using the custom manager application PlayDTMF.
 *
 * @param sess Session rnuning this applicationthe custom manager application PlayDTMF.
 * @param app The application structure
 * @param args Dtmf action args "ActionID DTMFDigit"
 * @return 0 if the call is found, -1 otherwise
 */
int
dtmf_exec(session_t *sess, app_t *app, const char *args)
{
    struct app_call_info *info;
    char actionid[ACTIONID_LEN];
    char digit[20];

    // This can only be done after authentication
    if (!session_test_flag(sess, SESS_FLAG_AUTHENTICATED)) {
        return NOT_AUTHENTICATED;
    }

    // Get Hangup parameteres
    if (sscanf(args, "%s %s", actionid, digit) != 2) {
        return INVALID_ARGUMENTS;
    }

    // Try to find the action info of the given actionid
    if ((info = get_call_info_from_id(sess, actionid)) && !isaac_strlen_zero(info->dchannel)) {
        // Send the digit to remote channel using PlayDTMF manager action
        ami_message_t msg;
        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: PlayDTMF");
        message_add_header(&msg, "Channel: %s", info->dchannel);
        message_add_header(&msg, "Digit: %s", digit);
        manager_write_message(manager, &msg);
        usleep(300 * 1000); // Wait 300 ms before accepting any other command
        session_write(sess, "DTMFOK\r\n");
    } else {
        session_write(sess, "DTMFFAILED ID NOT FOUND\r\n");
        return -1;
    }
    return 0;
}
예제 #3
0
void
test_session_tcp6(void) {
    lagopus_result_t ret;
    char cbuf[256] = {0};
    char sbuf[256] = {0};
    lagopus_session_t sesc, sess, sesa;
    struct addrunion dst, src;

    ret = session_create(SESSION_TCP6|SESSION_PASSIVE, &sess);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    addrunion_ipv6_set(&src, "::0");
    ret = session_bind(sess, &src, 10023);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    ret = session_create(SESSION_TCP6|SESSION_ACTIVE, &sesc);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    addrunion_ipv6_set(&dst, "::1");
    ret = session_connect(sesc, &dst, 10023, NULL, 0);
    if (ret == 0 || errno == EINPROGRESS)  {
        TEST_ASSERT(true);
    } else {
        TEST_ASSERT(false);
    }

    ret = session_accept(sess, &sesa);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_NOT_NULL(sesa);

    TEST_ASSERT_TRUE(session_is_alive(sess));
    TEST_ASSERT_TRUE(session_is_alive(sesc));
    TEST_ASSERT_TRUE(session_is_alive(sesa));

    snprintf(cbuf, sizeof(cbuf), "hogehoge\n");
    ret = session_write(sesc, cbuf, strlen(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));
    ret = session_read(sesa, sbuf, sizeof(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));

    ret = session_write(sesa, sbuf, strlen(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));
    ret = session_read(sesc, cbuf, sizeof(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));

    session_destroy(sesc);
    session_destroy(sesa);
    session_destroy(sess);
}
예제 #4
0
파일: app_call.c 프로젝트: irontec/isaac
/**
 * @brief Record action entry point
 *
 * Record action will start MixMonitor on given channel and will
 * set some variables for record post processing (in h extension).
 *
 * @param sess Session rnuning this application
 * @param app The application structure
 * @param args Hangup action args "ActionID" and "UniqueID"
 * @return 0 if the call is found, -1 otherwise
 */
int
recordstop_exec(session_t *sess, app_t *app, const char *args)
{
    struct app_call_info *info;
    char actionid[ACTIONID_LEN];

    // This can only be done after authentication
    if (!session_test_flag(sess, SESS_FLAG_AUTHENTICATED)) {
        return NOT_AUTHENTICATED;
    }

    // Get Hangup parameteres
    if (sscanf(args, "%s", actionid) != 1) {
        return INVALID_ARGUMENTS;
    }

    // Try to find the action info of the given actionid
    if ((info = get_call_info_from_id(sess, actionid)) && !isaac_strlen_zero(info->ochannel)) {

        // Check if this call is not being recorded
        if (!info->recording) {
            session_write(sess, "RECORDSTOPFAILED CALL NOT BEING RECORDED\r\n");
            return -1;
        }

        ami_message_t msg;
        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Command");
        message_add_header(&msg, "Command: mixmonitor stop %s", info->ochannel);
        manager_write_message(manager, &msg);

        // Flag this call as not being recorded
        info->recording = false;

        session_write(sess, "RECORDSTOPOK\r\n");
    } else {
        session_write(sess, "RECORDSTOPFAILED ID NOT FOUND\r\n");
        return -1;
    }
    return 0;
}
예제 #5
0
파일: app_call.c 프로젝트: irontec/isaac
/**
 * @brief Hold action entry point
 *
 * Hold action will send an event to the first channel generated by
 * CALL action using the manager application SIPNotifyChan. Not all
 * terminals support hold event.
 *
 * @param sess Session rnuning this application
 * @param app The application structure
 * @param args Hangup action args "ActionID"
 * @return 0 if the call is found, -1 otherwise
 */
int
hold_unhold_exec(session_t *sess, app_t *app, const char *args)
{
    struct app_call_info *info;
    char actionid[ACTIONID_LEN];
    char action[10];
    int i;

    // This can only be done after authentication
    if (!session_test_flag(sess, SESS_FLAG_AUTHENTICATED)) {
        return NOT_AUTHENTICATED;
    }

    // Get Hangup parameteres
    if (sscanf(args, "%s", actionid) != 1) {
        return INVALID_ARGUMENTS;
    }

    // Convert action to uppercase
    isaac_strcpy(action, app->name);
    for (i=0; action[i]; i++){
        action[i] = (char) toupper(action[i]);
    }

    // Try to find the action info of the given actionid
    if ((info = get_call_info_from_id(sess, actionid)) && !isaac_strlen_zero(info->ochannel)) {
        ami_message_t msg;
        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: SIPNotifyChan");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Event: %s", ((!strcasecmp(app->name, "Hold"))?"hold":"talk"));
        manager_write_message(manager, &msg);
        session_write(sess, "%sOK\r\n", action);
    } else {
        session_write(sess, "%sFAILED ID NOT FOUND\r\n", action);
        return -1;
    }
    return 0;
}
예제 #6
0
static int http_request(session *s, void *param)
{
	const char *filename = session_get_stash(s, HTTP_RESOURCE);
	char body[1024];
	const size_t len =
		sprintf(body,
		"<html>\n<title>404 NOT FOUND</title>\n<body>\n<h1>404 NOT FOUND: '%s'</h1>\n</body>\n</html>\n",
		filename
		);

	httpserver_response(s, 404, "NOT FOUND", len, "text/html");
	if (g_http_debug) printf("HTTP: %s", body);
	return session_write(s, body, len);
}
예제 #7
0
void
test_session_pair_stream(void) {
    lagopus_result_t ret;
    char cbuf[256] = {0};
    char sbuf[256] = {0};
    lagopus_session_t s[2];

    ret = session_pair(SESSION_UNIX_STREAM, s);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    snprintf(cbuf, sizeof(cbuf), "hogehoge\n");
    ret = session_write(s[0], cbuf, strlen(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));
    ret = session_read(s[1], sbuf, sizeof(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));

    ret = session_write(s[1], sbuf, strlen(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));
    ret = session_read(s[0], cbuf, sizeof(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));

    session_destroy(s[0]);
    session_destroy(s[1]);
}
예제 #8
0
static int linda_request(session *s, void *param)
{
	linda *l = (linda*)param;
	const char *ct = session_get_stash(s, "content-type");

	if (!strstr(ct, APPLICATION_JSON))
	{
		httpserver_response(s, 415, "UNSUPPORTED MEDIA TYPE", 0, NULL);
		return 1;
	}

	char *query = (char*)httpserver_get_content(s);

	if (!query)
	{
		httpserver_response(s, 400, "BAD REQUEST", 0, NULL);
		return 1;
	}

	const int dbsync = 0;
	hlinda *h = linda_begin(l);

	if (session_get_udata_flag(s, HTTP_GET))
	{
		const char *buf = NULL;

		if (!linda_rdp(h, query, &buf))
		{
			linda_end(h, dbsync);
			httpserver_response(s, 404, "NOT FOUND", 0, NULL);
			free(query);
			return 1;
		}

		size_t len = linda_get_length(h);
		linda_release(h);					// release the buf
		linda_end(h, dbsync);
		httpserver_response(s, 200, "OK", len, APPLICATION_JSON);
		if (g_http_debug) printf("LINDA: %s", buf);
		free((void*)buf);					// now free the buf
		session_write(s, buf, len);
	}
	else if (session_get_udata_flag(s, HTTP_POST))
	{
		const char *buf = NULL;

		if (!linda_inp(h, query, &buf))
		{
			linda_end(h, dbsync);
			httpserver_response(s, 404, "NOT FOUND", 0, NULL);
			free(query);
			return 1;
		}

		size_t len = linda_get_length(h);
		linda_release(h);					// release the buf
		linda_end(h, dbsync);
		httpserver_response(s, 200, "OK", len, APPLICATION_JSON);
		if (g_http_debug) printf("LINDA: %s", buf);
		free((void*)buf);					// now free the buf
		session_write(s, buf, len);
	}
	else if (session_get_udata_flag(s, HTTP_DELETE))
	{
		if (!linda_rm(h, query))
		{
			linda_end(h, dbsync);
			httpserver_response(s, 404, "NOT FOUND", 0, NULL);
			free(query);
			return 1;
		}

		linda_end(h, dbsync);
		httpserver_response(s, 200, "OK", 0, APPLICATION_JSON);
	}
	else if (session_get_udata_flag(s, HTTP_PUT))
	{
		if (!linda_out(h, query))
		{
			linda_end(h, dbsync);
			httpserver_response(s, 404, "NOT FOUND", 0, NULL);
			free(query);
			return 1;
		}

		linda_end(h, dbsync);
		httpserver_response(s, 200, "OK", 0, APPLICATION_JSON);
	}
	else
	{
		linda_end(h, dbsync);
		httpserver_response(s, 501, "NOT IMPLEMENTED", 0, NULL);
		free(query);
		return 1;
	}

	free(query);
	return 1;
}
예제 #9
0
void
test_session_tcp(void) {
    lagopus_result_t ret;
    char cbuf[256] = {0};
    char sbuf[256] = {0};
    bool b;
    lagopus_session_t sesc, sess, sesa, sesp[3];
    struct addrunion dst, src;

    ret = session_create(SESSION_TCP|SESSION_PASSIVE, &sess);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    addrunion_ipv4_set(&src, "0.0.0.0");
    ret = session_bind(sess, &src, 10022);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    ret = session_create(SESSION_TCP|SESSION_ACTIVE, &sesc);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    addrunion_ipv4_set(&dst, "127.0.0.1");
    ret = session_connect(sesc, &dst, 10022, NULL, 0);
    if (ret == 0 || errno == EINPROGRESS)  {
        TEST_ASSERT(true);
    } else {
        TEST_ASSERT(false);
    }

    session_write_event_set(sesc);
    session_read_event_set(sess);
    sesp[0] = sesc;
    sesp[1] = sess;
    ret = session_poll(sesp, 2, 1);
    TEST_ASSERT_EQUAL(2, ret);

    ret = session_is_writable(sesc, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_TRUE(b);

    ret = session_is_readable(sess, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_TRUE(b);

    ret = session_accept(sess, &sesa);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_NOT_NULL(sesa);

    TEST_ASSERT_TRUE(session_is_alive(sess));
    TEST_ASSERT_TRUE(session_is_alive(sesc));
    TEST_ASSERT_TRUE(session_is_alive(sesa));

    session_write_event_set(sesc);
    session_read_event_set(sess);
    session_read_event_set(sesa);
    sesp[0] = sesc;
    sesp[1] = sess;
    sesp[2] = sesa;
    ret = session_poll(sesp, 3, 1);
    TEST_ASSERT_EQUAL(1, ret);

    ret = session_is_writable(sesc, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_TRUE(b);

    ret = session_is_readable(sess, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_FALSE(b);

    ret = session_is_readable(sesa, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_FALSE(b);

    snprintf(cbuf, sizeof(cbuf), "hogehoge\n");
    ret = session_write(sesc, cbuf, strlen(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));

    session_read_event_set(sesa);
    sesp[0] = sesa;
    ret = session_poll(sesp, 1, 1);
    TEST_ASSERT_EQUAL(1, ret);

    ret = session_is_readable(sesa, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_TRUE(b);

    ret = session_read(sesa, sbuf, sizeof(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));
    ret = session_write(sesa, sbuf, strlen(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));
    ret = session_read(sesc, cbuf, sizeof(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));

    session_close(sesc);
    TEST_ASSERT_FALSE(session_is_alive(sesc));

    session_close(sesa);
    TEST_ASSERT_FALSE(session_is_alive(sesa));

    session_close(sess);
    TEST_ASSERT_FALSE(session_is_alive(sesa));

    session_write_event_set(sesc);
    session_read_event_set(sess);
    session_read_event_set(sesa);
    sesp[0] = sesc;
    sesp[1] = sess;
    sesp[2] = sesa;
    ret = session_poll(sesp, 3, 1);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_TIMEDOUT, ret);

    ret = session_is_writable(sesc, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_FALSE(b);

    ret = session_is_readable(sess, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_FALSE(b);

    ret = session_is_readable(sesa, &b);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_FALSE(b);

    session_destroy(sesc);
    session_destroy(sesa);
    session_destroy(sess);
}
예제 #10
0
void
test_session_fgets(void) {
    ssize_t ret;
    char *c;
#if 0
    char cbuf[256] = {0};
#endif
    char sbuf[256] = {0};
    lagopus_session_t sesc, sess, sesa, sesp[1];
    struct addrunion dst, src;

    ret = session_create(SESSION_TCP|SESSION_PASSIVE, &sess);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    addrunion_ipv4_set(&src, "0.0.0.0");
    ret = session_bind(sess, &src, 10022);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    ret = session_create(SESSION_TCP|SESSION_ACTIVE, &sesc);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    addrunion_ipv4_set(&dst, "127.0.0.1");
    ret = session_connect(sesc, &dst, 10022, NULL, 0);
    if (ret == 0 || errno == EINPROGRESS)  {
        TEST_ASSERT(true);
    } else {
        TEST_ASSERT(false);
    }

    ret = session_accept(sess, &sesa);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_NOT_NULL(sesa);

    TEST_ASSERT_TRUE(session_is_alive(sess));
    TEST_ASSERT_TRUE(session_is_alive(sesc));
    TEST_ASSERT_TRUE(session_is_alive(sesa));

    ret = session_printf(sesc, "%s", "hogehoge\n\nhoge");
    TEST_ASSERT_EQUAL(ret, strlen("hogehoge\n\nhoge"));

    session_read_event_set(sesa);
    sesp[0] = sesa;
    ret = session_poll(sesp, 1, 1);
    TEST_ASSERT_EQUAL(ret, 1);

    c = session_fgets(sbuf, 5, sesa);
    fprintf(stderr, "1.%s\n", sbuf);
    TEST_ASSERT_NOT_NULL(c);
    TEST_ASSERT_EQUAL(0, strncmp(sbuf, "hoge", 5));

    c = session_fgets(sbuf, 10, sesa);
    fprintf(stderr, "2.%s\n", sbuf);
    TEST_ASSERT_NOT_NULL(c);
    TEST_ASSERT_EQUAL(0, strncmp(sbuf, "hoge\n", 5));

    c = session_fgets(sbuf, 10, sesa);
    fprintf(stderr, "3.%s\n", sbuf);
    TEST_ASSERT_NOT_NULL(c);
    TEST_ASSERT_EQUAL(0, strncmp(sbuf, "\n", 1));

    c = session_fgets(sbuf, 5, sesa);
    fprintf(stderr, "4.%s\n", sbuf);
    TEST_ASSERT_NOT_NULL(c);
    TEST_ASSERT_EQUAL(0, strncmp(sbuf, "hoge", 5));

#if 0
    do {
        fprintf(stderr, "out:%s", sbuf);
        fgets(cbuf, sizeof(cbuf), stdin);
        fprintf(stderr, "in :%s", cbuf);
        session_write(sesc, cbuf, strlen(cbuf));
    } while (session_fgets(sbuf, sizeof(sbuf), sesa) != NULL);
#endif

    session_close(sesc);
    TEST_ASSERT_FALSE(session_is_alive(sesc));
    session_close(sesa);
    TEST_ASSERT_FALSE(session_is_alive(sesa));
    session_close(sess);
    TEST_ASSERT_FALSE(session_is_alive(sesa));

    session_destroy(sesc);
    session_destroy(sesa);
    session_destroy(sess);
}
예제 #11
0
void
test_session_tls(void) {
#if 0 /* this test code is not work, use openssl s_server/s_client commands for tls session tests. */
    lagopus_result_t ret;
    char cbuf[256] = {0};
    char sbuf[256] = {0};
    lagopus_session_t sesc, sess, sesa;
    struct addrunion src, dst;

    session_tls_set_ca_dir("ca");
    session_tls_set_server_cert("./server1.pem");
    session_tls_set_server_key("./server1_key_nopass.pem");
    session_tls_set_client_key("./client1_key_nopass.pem");

    ret = session_create(SESSION_TCP|SESSION_PASSIVE|SESSION_TLS, &sess);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    addrunion_ipv4_set(&src, "0.0.0.0");
    ret = session_bind(sess, &src, 10024);

    addrunion_ipv4_set(&dst, "127.0.0.1");
    ret = session_create(SESSION_TCP|SESSION_TLS|SESSION_ACTIVE, &sesc);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);

    ret = session_connect(sesc, &dst, 10024, &dst, 0);
    if (ret == 0 || errno == EINPROGRESS)  {
        TEST_ASSERT(true);
    } else {
        TEST_ASSERT(false);
    }

    ret = session_accept(sess, &sesa);
    TEST_ASSERT_EQUAL(LAGOPUS_RESULT_OK, ret);
    TEST_ASSERT_NOT_NULL(sesa);

    TEST_ASSERT_TRUE(session_is_alive(sess));
    TEST_ASSERT_TRUE(session_is_alive(sesa));

    ret = session_read(sesa, sbuf, sizeof(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));

    ret = session_write(sesa, sbuf, strlen(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));

    TEST_ASSERT_TRUE(session_is_alive(sesc));

    snprintf(cbuf, sizeof(cbuf), "hogehoge\n");
    ret = session_write(sesc, cbuf, strlen(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));
    ret = session_read(sesa, sbuf, sizeof(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));

    ret = session_write(sesa, sbuf, strlen(sbuf));
    TEST_ASSERT_EQUAL(ret, strlen(sbuf));
    ret = session_read(sesc, cbuf, sizeof(cbuf));
    TEST_ASSERT_EQUAL(ret, strlen(cbuf));

    session_destroy(sesc);
    session_destroy(sesa);
    session_destroy(sess);
#endif
}
예제 #12
0
파일: app_call.c 프로젝트: irontec/isaac
/**
 * @brief Record action entry point
 *
 * Record action will start MixMonitor on given channel and will
 * set some variables for record post processing (in h extension).
 *
 * @param sess Session rnuning this application
 * @param app The application structure
 * @param args Hangup action args "ActionID" and "UniqueID"
 * @return 0 if the call is found, -1 otherwise
 */
int
record_exec(session_t *sess, app_t *app, const char *args)
{
    struct app_call_info *info;
    char actionid[ACTIONID_LEN];
    char filename[128];
    time_t timer;
    char timestr[25];
    struct tm* tm_info;

    // This can only be done after authentication
    if (!session_test_flag(sess, SESS_FLAG_AUTHENTICATED)) {
        return NOT_AUTHENTICATED;
    }

    // Get Hangup parameteres
    if (sscanf(args, "%s %s", actionid, filename) != 2) {
        return INVALID_ARGUMENTS;
    }

    // Try to find the action info of the given actionid
    if ((info = get_call_info_from_id(sess, actionid)) && !isaac_strlen_zero(info->ochannel)) {

        // Check if this call is already being recorded
        if (info->recording) {
            session_write(sess, "RECORDFAILED CALL IS ALREADY BEING RECORDED\r\n");
            return -1;
        }

        ami_message_t msg;
        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: MixMonitor");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "File: %s/%s.wav", call_config.record_path, filename);
        manager_write_message(manager, &msg);

        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_MODULO", info->ouid);
        message_add_header(&msg, "Value: %sCC", info->grabaciones_modulo);
        manager_write_message(manager, &msg);

        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_PLATAFORMA", info->ouid);
        message_add_header(&msg, "Value: %s", info->grabaciones_plataforma);
        manager_write_message(manager, &msg);

        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_TIPO", info->ouid);
        message_add_header(&msg, "Value: %son-demand_ISAAC", info->grabaciones_tipo);
        manager_write_message(manager, &msg);

        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_ORIGEN", info->ouid);
        message_add_header(&msg, "Value: %s%s",info->grabaciones_origen,session_get_variable(sess, "AGENT"));
        manager_write_message(manager, &msg);

        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_DESTINO", info->ouid);
        message_add_header(&msg, "Value: %s%s",info->grabaciones_destino, info->destiny);
        manager_write_message(manager, &msg);

        time(&timer);
        tm_info = localtime(&timer);
        strftime(timestr, 25, "%Y:%m:%d_%H:%M:%S", tm_info);
        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_FECHA_HORA", info->ouid);
        message_add_header(&msg, "Value: %s%s", info->grabaciones_fecha_hora, timestr);
        manager_write_message(manager, &msg);

        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_RUTA", info->ouid);
        message_add_header(&msg, "Value: %s%s", info->grabaciones_ruta, call_config.record_path);
        manager_write_message(manager, &msg);
        
        memset(&msg, 0, sizeof(ami_message_t));
        message_add_header(&msg, "Action: Setvar");
        message_add_header(&msg, "Channel: %s", info->ochannel);
        message_add_header(&msg, "Variable: GRABACIONES_%s_FICHERO", info->ouid);
        message_add_header(&msg, "Value: %s%s.wav", info->grabaciones_fichero, filename);
        manager_write_message(manager, &msg);

        // Flag this call as being recorded
        info->recording = true;

        session_write(sess, "RECORDOK\r\n");
    } else {
        session_write(sess, "RECORDFAILED ID NOT FOUND\r\n");
        return -1;
    }
    return 0;
}
예제 #13
0
파일: app_call.c 프로젝트: irontec/isaac
/**
 * @brief Writes to session CALLEVENT messages
 *
 * This function sends the CALLEVENTS to a session when some filter
 * events triggers. It is used for Agent and Remote channel events.\n
 *
 * This function will be callbacked when one of this happens:\n
 *  - A channel sets ACTIONID variable: This gave us leg1 channel\n
 *  - This channel begins a Dial Action: This gave us the second leg\n
 *  - Events on any of these two channels\n
 *
 * @param filter Triggering filter structure
 * @param msg Matching message from Manager
 * @return 0 in all cases
 */
int
call_state(filter_t *filter, ami_message_t *msg)
{
    // Get Call information
    struct app_call_info *info = (struct app_call_info *) filter_get_userdata(filter);
    // Get message event
    const char *event = message_get_header(msg, "Event");
    char from[80], state[80], uniqueid[80], response[256];
    bool finished = false;
 
    // Initialize arrays
    memset(from,        0, sizeof(from));
    memset(state,       0, sizeof(state));
    memset(uniqueid,    0, sizeof(uniqueid));
    memset(response,    0, sizeof(response));

    // So this leg is first one or second one?
    if (!strcasecmp(message_get_header(msg, "UniqueID"), info->ouid)) {
        isaac_strcpy(from, "AGENT");
    } else {
        isaac_strcpy(from, "REMOTE");
    }

    // Send CallStatus message depending on received event
    if (!strcasecmp(event, "Hangup")) {
        // Print status message dpending on Hangup Cause
        const char *cause = message_get_header(msg, "Cause");
        if (!strcasecmp(cause, "0") || !strcasecmp(cause, "21")) {
            isaac_strcpy(state, "ERROR");
        } else if (!strcasecmp(cause, "16")) {
            isaac_strcpy(state, "HANGUP");
        } else if (!strcasecmp(cause, "17")) {
            isaac_strcpy(state, "BUSY");
        } else {
            sprintf(state, "UNKNOWNHANGUP %s", cause);
        }

        // This call info has ended
        finished = true;

    } else if (!strcasecmp(event, "MusicOnHold")) {
        if (!strcasecmp(message_get_header(msg, "State"), "Start")) {
            isaac_strcpy(state, "HOLD");
        } else {
            isaac_strcpy(state, "UNHOLD");
        }

        // In this case, the channel that receives the Hold event is the
        // one that is being hold, not holding. So we should swap the
        // AGENT <-> REMOVE value
        if (!strcasecmp(message_get_header(msg, "UniqueID"), info->ouid)) {
            isaac_strcpy(from, "REMOTE");
        } else {
            isaac_strcpy(from, "AGENT");
        }

    } else if (!strcasecmp(event, "Newstate")) {
        // Print status message depending on Channel Status
        const char *chanstate = message_get_header(msg, "ChannelState");
        if (!strcasecmp(chanstate, "5")) {
            isaac_strcpy(state, "RINGING");
        } else if (!strcasecmp(chanstate, "6")) {
            isaac_strcpy(state, "ANSWERED");
        }
    } else if (!strcasecmp(event, "Rename")) {
        if (!strcasecmp(message_get_header(msg, "UniqueID"), info->ouid)) {
            strcpy(info->ochannel, message_get_header(msg, "NewName"));
        }
    } else if (!strcasecmp(event, "VarSet")) {
        const char *varvalue = message_get_header(msg, "Value");
        const char *varname = message_get_header(msg, "Variable");

        // Progress event on cellphones
        if (!strcasecmp(varvalue, "SIP 183 Session Progress")) {
            isaac_strcpy(state, "PROGRESS");
        }

        // Update recording variables
        if (!strncasecmp(varname, "GRABACIONES_", 12)) {
            char recordvar[256],recorduniqueid[80], grabaciones[80], recordtype[80];
            isaac_strcpy(recordvar, varname);
            if (sscanf(recordvar, "%[^_]_%[^_]_%s", grabaciones, recorduniqueid, recordtype) == 3) {
                if (!strcasecmp(recordtype, "MODULO"))     sprintf(info->grabaciones_modulo, "%s;", varvalue);
                if (!strcasecmp(recordtype, "TIPO"))       sprintf(info->grabaciones_tipo, "%s;", varvalue);
                if (!strcasecmp(recordtype, "PLATAFORMA")) sprintf(info->grabaciones_plataforma, "%s;", varvalue);
                if (!strcasecmp(recordtype, "ORIGEN"))     sprintf(info->grabaciones_origen, "%s;", varvalue);
                if (!strcasecmp(recordtype, "DESTINO"))    sprintf(info->grabaciones_destino, "%s;", varvalue);
                if (!strcasecmp(recordtype, "FECHA_HORA")) sprintf(info->grabaciones_fecha_hora, "%s;", varvalue);
                if (!strcasecmp(recordtype, "RUTA"))       sprintf(info->grabaciones_ruta, "%s;", varvalue);
                if (!strcasecmp(recordtype, "FICHERO"))    sprintf(info->grabaciones_fichero, "%s;", varvalue);
            } else {
                isaac_log(LOG_WARNING, "Unhandled record variable %s\n", varname);
            }
        }

        // A channel has set ACTIONID var, this is our leg1 channel. It will Dial soon!
        if (!strcasecmp(varname, "ACTIONID")) {
            // Get the UniqueId from the agent channel
            isaac_strcpy(info->ouid, message_get_header(msg, "UniqueID"));
            // Store provisional Channel Name
            isaac_strcpy(info->ochannel, message_get_header(msg, "Channel"));
            // This messages are always from agent
            isaac_strcpy(from, "AGENT");

            // Register a Filter for the agent statusthe custom manager application PlayDTMF.
            info->ofilter = filter_create_async(filter->sess, call_state);
            filter_new_condition(info->ofilter, MATCH_REGEX, "Event", "Hangup|MusicOnHold|Newstate|Rename|VarSet|Dial");
            filter_new_condition(info->ofilter, MATCH_EXACT, "UniqueID", info->ouid);
            filter_set_userdata(info->ofilter, (void*) info);
            filter_register(info->ofilter);

            // Tell the client the channel is going on!
            isaac_strcpy(state, "STARTING"); 
        }
    } else if (!strcasecmp(event, "Dial") && !strcasecmp(message_get_header(msg, "SubEvent"),
            "Begin")) {
        // Get the UniqueId from the agent channel
        strcpy(info->duid, message_get_header(msg, "DestUniqueID"));
        strcpy(info->dchannel, message_get_header(msg, "Destination"));

        // Register a Filter for the agent status
        info->dfilter = filter_create_async(filter->sess, call_state);
        filter_set_userdata(info->dfilter, info);
        filter_new_condition(info->ofilter, MATCH_REGEX, "Event", "Hangup|MusicOnHold|Newstate|Rename|VarSet|Dial");
        filter_new_condition(info->dfilter, MATCH_EXACT, "UniqueID", info->duid);
        filter_register(info->dfilter);

        // This messages are always from agent
        isaac_strcpy(from, "REMOTE");

        // Store the call state
        isaac_strcpy(state, "STARTING");
    }


    // Built the event message
    if (strlen(state)) {
        // Add Uniqueid to response if requested
        if (info->print_uniqueid) {
            isaac_strcpy(uniqueid, !strcasecmp(from, "AGENT")?info->ouid:info->duid);
            sprintf(response, "CALLSTATUS %s %s %s %s\r\n", info->actionid, uniqueid, from, state);
        } else {
            sprintf(response, "CALLSTATUS %s %s %s\r\n", info->actionid, from, state);
        }

        // Send this message to other clients if requested
        if (info->broadcast) {
            session_write_broadcast(filter->sess, response);
        } else {
            session_write(filter->sess, response);
        }
    }

    // We dont expect more info about this filter, it's safe to unregister it here
    if (finished)
        filter_unregister(filter);

    return 0;
}
예제 #14
0
int
service_write (dk_session_t * ses, char *buffer, int bytes)
{
  USE_GLOBAL
  int last_written = 0;
  int rc;

  DBG_CHECK_WRITE_FAIL (ses);
  if (!ses->dks_session)
    {
      longjmp_splice (&SESSION_SCH_DATA (ses)->sio_write_broken_context, 1);
    }
  while (bytes > 0)
    {
      without_scheduling_tic ();
      rc = session_write (ses->dks_session, &(buffer[last_written]), bytes);
      restore_scheduling_tic ();
      if (rc == 0)
	PROCESS_ALLOW_SCHEDULE ();
      if (rc > 0)
	{
	  bytes = bytes - rc;
	  last_written = last_written + rc;
	}
      if (rc < 0)
	{
	  if (SESSTAT_W_ISSET (ses->dks_session, SST_INTERRUPTED))
	    {
	      PROCESS_ALLOW_SCHEDULE ();
	    }
	  else if (SESSTAT_W_ISSET (ses->dks_session, SST_BLOCK_ON_WRITE))
	    {
	      if (!_thread_sched_preempt)
		freeze_thread_write (ses);
	      else
		{
		  timeout_t tv = { 100, 0 };
		retry:
		  tcpses_is_write_ready (ses->dks_session, &tv);
		  if (SESSTAT_W_ISSET (ses->dks_session, SST_TIMED_OUT))
		    {
		      scheduler_io_data_t * sio = SESSION_SCH_DATA (ses);
		      if (sio->sio_w_timeout_hook && sio->sio_w_timeout_hook (ses))
			{
			  SESSTAT_W_CLR (ses->dks_session, SST_TIMED_OUT);
			  goto retry;
			}
		      SESSTAT_W_SET (ses->dks_session, SST_BROKEN_CONNECTION);
		      longjmp_splice (&SESSION_SCH_DATA (ses)->sio_write_broken_context, 1);
		    }
		}
	    }
	  else
	    {
	      ses->dks_bytes_sent += last_written;
	      ss_dprintf_2 (("Unrecognized I/O error rc=%d errno=%d  in service_write", rc, errno));
	      SESSTAT_W_CLR (ses->dks_session, SST_OK);
	      SESSTAT_W_SET (ses->dks_session, SST_BROKEN_CONNECTION);
	      longjmp_splice (&SESSION_SCH_DATA (ses)->sio_write_broken_context, 1);
	    }
	}
    }
  ses->dks_bytes_sent += last_written;
  return 0;
}