/* $Id: rtpproxy_stream.c,v 1.2 2008/11/04 22:28:04 sobomax Exp $
 *
 * Copyright (C) 2008 Sippy Software, Inc., http://www.sippysoft.com
 *
 * This file is part of ser, a free SIP server.
 *
 * ser is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * For a license to use the ser software under conditions
 * other than those described here, or to purchase support for this
 * software, please contact iptel.org by e-mail at the following addresses:
 *    info@iptel.org
 *
 * ser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <stdio.h>
#include <sys/uio.h>

#include "../../ip_addr.h"
#include "../../parser/msg_parser.h"
#include "../../sr_module.h"
#include "../../ut.h"
#include "rtpproxy.h"
#include "rtpproxy_funcs.h"

int
fixup_var_str_int(void **param, int param_no)
{
    int ret;
    pv_elem_t *model;
    str s;

    if (param_no == 1) {
        model = NULL;
        s.s = (char *)(*param);
        s.len = strlen(s.s);
        if (pv_parse_format(&s, &model) < 0) {
            LM_ERR("wrong format[%s]!\n", (char *)(*param));
            return E_UNSPEC;
        }
        if (model == NULL) {
            LM_ERR("empty parameter!\n");
            return E_UNSPEC;
        }
        *param = (void *)model;
    } else if (param_no == 2) {
	/* According to
	 * http://www.kamailio.org/docs/modules/1.5.x/nathelper.html#rtpproxy_stream2xxx
	 * this could be -1 */
	s.s = (char *)(*param);
	s.len = strlen(s.s);
	if (str2sint(&s, &ret)==0) {
		pkg_free(*param);
		*param = (void *)(long)ret;
        } else {
            LM_ERR("bad number <%s>\n", (char *)(*param));
            return E_CFG;
        }
    }
    return 0;
}

static int
rtpproxy_stream(struct sip_msg* msg, str *pname, int count, int stream2uac)
{
    int nitems;
    str callid, from_tag, to_tag;
    struct rtpp_node *node;
    char cbuf[16];
    struct iovec v[] = {
        {NULL,        0},
        {cbuf,        0}, /* 1 P<count> */
        {" ",         1},
        {NULL,        0}, /* 3 callid */
        {" ",         1},
        {NULL,        0}, /* 5 pname */
        {" session ", 9},
        {NULL,        0}, /* 7 from tag */
        {";1 ",       3},
        {NULL,        0}, /* 9 to tag */
        {";1",        2}
    };

    if (get_callid(msg, &callid) == -1 || callid.len == 0) {
        LM_ERR("can't get Call-Id field\n");
        return -1;
    }
    if (get_to_tag(msg, &to_tag) == -1) {
        LM_ERR("can't get To tag\n");
        return -1;
    }
    if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
        LM_ERR("can't get From tag\n");
        return -1;
    }
    v[1].iov_len = sprintf(cbuf, "P%d", count);
    STR2IOVEC(callid, v[3]);
    STR2IOVEC(*pname, v[5]);
    node = select_rtpp_node(callid, 1);
    if (!node) {
        LM_ERR("no available proxies\n");
        return -1;
    }
    if (node->rn_ptl_supported == 0) {
        LM_ERR("required functionality is not "
          "supported by the version of the RTPproxy running on the selected "
          "node.  Please upgrade the RTPproxy and try again.\n");
        return -1;
    }
    set_rtp_inst_pvar(msg, &node->rn_url);
    nitems = 11;
    if (stream2uac == 0) {
        if (to_tag.len == 0)
            return -1;
        STR2IOVEC(to_tag, v[7]);
        STR2IOVEC(from_tag, v[9]);
    } else {
        STR2IOVEC(from_tag, v[7]);
        STR2IOVEC(to_tag, v[9]);
        if (to_tag.len <= 0)
            nitems -= 2;
    }
    send_rtpp_command(node, v, nitems);

    return 1;
}

static int
rtpproxy_stream2_f(struct sip_msg *msg, char *str1, int count, int stream2uac)
{
    str pname;

    if (str1 == NULL || pv_printf_s(msg, (pv_elem_p)str1, &pname) != 0)
	return -1;
    return rtpproxy_stream(msg, &pname, count, stream2uac);
}

int
rtpproxy_stream2uac2_f(struct sip_msg* msg, char* str1, char* str2)
{

    return rtpproxy_stream2_f(msg, str1, (int)(long)str2, 1);
}

int
rtpproxy_stream2uas2_f(struct sip_msg* msg, char* str1, char* str2)
{

    return rtpproxy_stream2_f(msg, str1, (int)(long)str2, 0);
}

static int
rtpproxy_stop_stream(struct sip_msg* msg, int stream2uac)
{
    int nitems;
    str callid, from_tag, to_tag;
    struct rtpp_node *node;
    struct iovec v[] = {
        {NULL,        0},
        {"S",         1}, /* 1 */
        {" ",         1},
        {NULL,        0}, /* 3 callid */
        {" ",         1},
        {NULL,        0}, /* 5 from tag */
        {";1 ",       3},
        {NULL,        0}, /* 7 to tag */
        {";1",        2}
    };

    if (get_callid(msg, &callid) == -1 || callid.len == 0) {
        LM_ERR("can't get Call-Id field\n");
        return -1;
    }
    if (get_to_tag(msg, &to_tag) == -1) {
        LM_ERR("can't get To tag\n");
        return -1;
    }
    if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
        LM_ERR("can't get From tag\n");
        return -1;
    }
    STR2IOVEC(callid, v[3]);
    node = select_rtpp_node(callid, 1);
    if (!node) {
        LM_ERR("no available proxies\n");
        return -1;
    }
    if (node->rn_ptl_supported == 0) {
        LM_ERR("required functionality is not "
          "supported by the version of the RTPproxy running on the selected "
          "node.  Please upgrade the RTPproxy and try again.\n");
        return -1;
    }
    set_rtp_inst_pvar(msg, &node->rn_url);
    nitems = 9;
    if (stream2uac == 0) {
        if (to_tag.len == 0)
            return -1;
        STR2IOVEC(to_tag, v[5]);
        STR2IOVEC(from_tag, v[7]);
    } else {
        STR2IOVEC(from_tag, v[5]);
        STR2IOVEC(to_tag, v[7]);
        if (to_tag.len <= 0)
            nitems -= 2;
    }
    send_rtpp_command(node, v, nitems);

    return 1;
}

int
rtpproxy_stop_stream2uac2_f(struct sip_msg* msg, char* str1, char* str2)
{

    return rtpproxy_stop_stream(msg, 1);
}

int
rtpproxy_stop_stream2uas2_f(struct sip_msg* msg, char* str1, char* str2)
{

    return rtpproxy_stop_stream(msg, 0);
}