#include "./include/sip_pub.h"
#include "./include/sip.h"
#include "./include/sip_const.h"
#include "./include/sip_struct.h"
#include "./include/sip_ext.h"
#include "./include/sip_msg.h"
#include "./include/sip_msg_encode.h"
#include "./include/sip_debug.h"

char *sip_uri_escape_nonascii_and_nondef(char *string, char *def)
{
    WORD alloc = strlen(string) + 1;
    WORD length;
    BYTE in;
    WORD newLen = alloc;
    int index = 0;
    char *tmp;
    int i;

    length = alloc - 1;
    while (length--)
    {
        in = *string;

        i = 0;
        tmp = NULL;
        if (sip_is_alphanum(in))
            tmp = string;
        else
        {
            for (; def[i] != '\0' && def[i] != in; i++)
            {
            }
            if (def[i] != '\0')
                tmp = string;
        }
        if (tmp == NULL)
        {
            // encode it
            newLen += 2;          // the size grows with two, since this'll become a %XX
            if (newLen > alloc)
            {
                alloc *= 2;
            }
            sprintf (&sipEscapeBuf[index], "%%%02X", in);
            index += 3;
        }
        else
        {
            // just copy this
            sipEscapeBuf[index++] = in;
        }
        string++;
    }
    sipEscapeBuf[index] = 0;                // terminate it

    return sipEscapeBuf;
}

/* user =  *( unreserved / escaped / user-unreserved ) */
char *userInfoDef = /* implied _ALPHANUM_ */ _MARK__USER_UNRESERVED_;

char *sip_uri_escape_user_info(char *string)
{
  return sip_uri_escape_nonascii_and_nondef(string, userInfoDef);
}

/* user =  *( unreserved / escaped / user-unreserved ) */
char *passwordDef = _MARK__PWORD_UNRESERVED_;

char *sip_uri_escape_password(char *string)
{
  return sip_uri_escape_nonascii_and_nondef(string, passwordDef);
}

char *uriParamDef = _MARK__URI_PARAM_UNRESERVED_;

char *sip_uri_escape_uri_param(char *string)
{
  return sip_uri_escape_nonascii_and_nondef(string, uriParamDef);
}

char *headerParamDef = _MARK__HEADER_PARAM_UNRESERVED_;

char *sip_uri_escape_header_param(char *string)
{
  return sip_uri_escape_nonascii_and_nondef (string, headerParamDef);
}

int sip_encode_para_name(char *dest, BYTE pname)
{
    if (dest == NULL)
    {
        return 0;
    }

    switch (pname)
    {
        case SIP_API_PNAME_TAG:
            sprintf(dest, "%s", SIP_PNAME_TAG);
            break;
        case SIP_API_PNAME_BRANCH:
            sprintf(dest, "%s", SIP_PNAME_BRANCH);
            break;
        case SIP_API_PNAME_EXPIRES:
            sprintf(dest, "%s", SIP_PNAME_EXPIRES);
            break;
        case SIP_API_PNAME_USER:
            sprintf(dest, "%s", SIP_PNAME_USER);
            break;
        case SIP_API_PNAME_LR:
            sprintf(dest, "%s", SIP_PNAME_LR);
            break;
        case SIP_API_PNAME_BOUNDARY:
            sprintf(dest, "%s", SIP_PNAME_BOUNDARY);
            break;
        case SIP_API_PNAME_HANDLING:
            sprintf(dest, "%s", SIP_PNAME_HANDLING);
            break;
        case SIP_API_PNAME_TRANSPORT:
            sprintf(dest, "%s", SIP_PNAME_TRANSPORT);
            break;
        case SIP_API_PNAME_RPOTR:
            sprintf(dest, "%s", SIP_PNAME_RPORT);
            break;
        case SIP_API_PNAME_VERSION:
            sprintf(dest, "%s", SIP_PNAME_VERSION);
            break;
        case SIP_API_PNAME_BASE:
            sprintf(dest, "%s", SIP_PNAME_BASE);
            break;
        default:
            return 0;//return -1
    }
    
    return 0;
}

int sip_encode_para(char *dest, SIP_GEN_PARA *para, BYTE last, BYTE escape)
{
    char param[128] = "";
    char name[128]= "";
    char value[128] = "";
    char *pname, *pvalue;
    
    if ((dest == NULL) || (para == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_para: dest or para is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_para_name(name, para->paraName) < 0)
        return -1;
    
    if (escape)
        pname = sip_uri_escape_uri_param(name);
    else
        pname = name;

    strcpy(param, pname);
    
    if (para->paraType == SIP_API_PTYPE_STRING)
        sprintf(value, "%s", para->para.paraStr);
    else if (para->paraType == SIP_API_PTYPE_VALUE)
    {
        if (para->para.paraVal[0] == 0xFFFFFFFF)
            strcpy(value, "");
        else
            sprintf(value, "%ld", para->para.paraVal[0]);
    }

    if ((para->paraType == SIP_API_PTYPE_STRING) ||
        (para->paraType == SIP_API_PTYPE_VALUE))
    {
        if (escape)
            pvalue = sip_uri_escape_uri_param(value);
        else
            pvalue = value;
    }
    
    if ((para->paraType == SIP_API_PTYPE_STRING) ||
        (para->paraType == SIP_API_PTYPE_VALUE))
    {
        if (pvalue[0] != '\0')
        {
            strcat(param, "=");
            strcat(param, pvalue);
        }
    }
    
    if (last == 0)//((last == 0) && (param[0] != '\0'))
        strcat(param, ";");
    
    strcat(dest, param);
    
    return 0;
}

int sip_encode_params(char *dest, SIP_GEN_PARAMS *params, BYTE escape)
{
    BYTE    i, last = 0;
    
    if ((dest == NULL) || (params == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_params: dest or params is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    strcpy(dest, "");
    
    if (params->paraNum == 0)
        return -2;
    
    for (i = 0; i < params->paraNum; i++)
    {
        if (i == (params->paraNum - 1))
            last = 1;
        if (sip_encode_para(dest, &params->para[i], last, escape) < 0)
            return -1;
        
    }
    
    return 0;
}

int sip_encode_url(char *dest, SIP_URI *url, BYTE flag)
{
    char    params[128];
    char    port[16];
    int     result;
    char    *userName;

    if ((dest == NULL) || (url == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_url: dest or url is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((result = sip_encode_params(params, &url->params, 0)) == -1)
        return -1;
    
    strcpy(port, "");
    if (url->port != 0)
        sprintf(port, ":%d", url->port);
    
    if ((flag & SIP_ENCODE_URL_NO_USER_PART) == SIP_ENCODE_URL_NO_USER_PART)
    {
        if ((flag & SIP_ENCODE_URL_NO_BRACKETS) == SIP_ENCODE_URL_NO_BRACKETS)
        {
            if (result == 0)
                sprintf(dest, "%s%s;%s", url->host.addr.domain, port, params);
            else
                sprintf(dest, "%s%s", url->host.addr.domain, port);
        }
        else
        {
            if (result == 0)
                sprintf(dest, "<sip:%s%s;%s>", url->host.addr.domain, port, params);
            else
                sprintf(dest, "<sip:%s%s>", url->host.addr.domain, port);
        }
    }
    else
    {
        userName = sip_uri_escape_user_info (url->userName);
        if ((flag & SIP_ENCODE_URL_NO_BRACKETS) == SIP_ENCODE_URL_NO_BRACKETS)
        {
            if (result == 0)
            {
                if (*userName == '\0')
                    sprintf(dest, "sip:%s%s;%s", url->host.addr.domain, port, params);
                else
                    sprintf(dest, "sip:%s@%s%s;%s", userName, url->host.addr.domain, port, params);
            }
            else
            {
                if (*userName == '\0')
                    sprintf(dest, "sip:%s%s", url->host.addr.domain, port);
                else
                    sprintf(dest, "sip:%s@%s%s", userName, url->host.addr.domain, port);
            }
        }
        else
        {
            if (result == 0)
            {
                if (*userName == '\0')
                    sprintf(dest, "<sip:%s%s;%s>", url->host.addr.domain, port, params);
                else
                    sprintf(dest, "<sip:%s@%s%s;%s>", userName, url->host.addr.domain, port, params);
            }
            else
            {
                if (*userName == '\0')
                    sprintf(dest, "<sip:%s%s>", url->host.addr.domain, port);
                else
                    sprintf(dest, "<sip:%s@%s%s>", userName, url->host.addr.domain, port);
            }
        }
    }
    
    return 0;
}

int sip_encode_via_url(char *dest, SIP_VIA_URI *url, BYTE flag)
{
    char    port[16];

    if ((dest == NULL) || (url == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_url: dest or url is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    strcpy(port, "");
    if (url->port != 0)
        sprintf(port, ":%d", url->port);
    
    if ((flag & SIP_ENCODE_URL_NO_BRACKETS) == SIP_ENCODE_URL_NO_BRACKETS)
    {
        sprintf(dest, "%s%s", url->domain, port);
    }
    else
    {
        sprintf(dest, "<sip:%s%s>", url->domain, port);
    }
    
    return 0;
}

int sip_transport_encode_start_line(char *dest, SIP_API_STRUCT *sipApiMsg)
{
    char            ver[8];
    char            statusCode[8];
    char            method[16];
    char            uri[128];
    SIP_START_LINE  *startLine;

    if ((dest == NULL) || (sipApiMsg == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_start_line: dest or sipApiMsg is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    startLine = &sipApiMsg->sipApiMsg.sipMsg.sipStartLine;
    
    if (sipApiMsg->sipApiType == SIP_API_RES_MSG)
    {
        if (sip_ver_api_conv(ver, &startLine->sipVersion, SIP_API_TO_STR) < 0)
            return -1;
        sprintf(statusCode, "%d", startLine->statusCode);
        sprintf((char *)sipEncBuf, "%s %s %s\r\n", ver, statusCode, startLine->reasonPhrase);
    }
    else
    {
        if (sip_method_api_conv(method, &startLine->sipMethod, SIP_API_TO_STR) < 0)
            return -1;
        sip_encode_url(uri, &startLine->requestUri, SIP_ENCODE_URL_NO_BRACKETS);
        if (sip_ver_api_conv(ver, &startLine->sipVersion, SIP_API_TO_STR) < 0)
            return -1;
        sprintf((char *)sipEncBuf, "%s %s %s\r\n", method, uri, ver);
    }
    
    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_call_id(char *dest, SIP_HDR_CALL_ID *callId)
{
    if ((dest == NULL) || (callId == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_call_id: dest or callId is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    callId->value[SIP_MAX_CALL_ID_LEN - 1] = '\0';
    if (callId->host[0] != '\0')
        sprintf((char *)sipEncBuf, "Call-ID: %s@%s\r\n", callId->value, callId->host);
    else
        sprintf((char *)sipEncBuf, "Call-ID: %s\r\n", callId->value);
    
    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_cseq(char *dest, SIP_HDR_CSEQ *cseq)
{
    char method[32];

    if ((dest == NULL) || (cseq == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_cseq: dest or cseq is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    } 
   
    if (sip_method_api_conv(method, &cseq->method, SIP_API_TO_STR) < 0)
        return -1;

    sprintf((char *)sipEncBuf, "CSeq: %ld %s\r\n", cseq->value, method);
    
    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_accept(char *dest, SIP_HDR_ACCEPT *accept)
{
    char        type[32];
    char        subType[32];
    char        params[64];

    if ((dest == NULL) || (accept == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_accept: dest or accept is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_accept_type_api_conv(type, &accept->type, SIP_API_TO_STR) < 0)
        return -1;

    if (sip_accept_sub_type_api_conv(subType,  &accept->subType, SIP_API_TO_STR) < 0)
        return -1;

    if (sip_encode_params(params, &accept->params, 0) < 0)
    {
        sprintf((char *)sipEncBuf, "Accept: %s/%s\r\n", type, subType);
    }
    else
    {
        sprintf((char *)sipEncBuf, "Accept: %s/%s;%s\r\n", type, subType, params);
    }

    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_accept_encoding(char *dest, SIP_HDR_ACCEPT_ENCODING*accept_encoding)
{
    char     encoding[32];
    char     params[64];

    if ((dest == NULL) || (accept_encoding == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_accept_encoding: dest or accept_encoding is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_accept_encoding_api_conv(encoding, &accept_encoding->acceptEncoding, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode accept encoding failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_params(params, &accept_encoding->params, 0) < 0)
    {
        sprintf((char *)sipEncBuf, "Accept-Encoding: %s\r\n", encoding);
    }
    else
    {
        sprintf((char *)sipEncBuf, "Accept-Encoding: %s;%s\r\n", encoding, params);
    }

    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_accept_language(char *dest, SIP_HDR_ACCEPT_LANGUAGE *accept_language)
{
    char     language[32];
    char     params[64];

    if ((dest == NULL) || (accept_language == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_accept_language: dest or accept_language is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_accept_language_api_conv(language, &accept_language->acceptLanguage, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode accept language failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_params(params,&accept_language->params, 0) < 0)
    {
        sprintf((char *)sipEncBuf, "Accept-Language: %s\r\n", language);
    }
    else
    {
        sprintf((char *)sipEncBuf, "Accept-Language: %s;%s\r\n", language, params);
    }

    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_allow(char *dest, SIP_HDR_ALLOW *allow)
{
    int      i;
    char     tmp[32];
    char     buf[64] = "";

    if ((dest == NULL) || (allow == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_allow: dest or allow is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    for (i = 0; i < allow->num; i++)
    {
        if (i > 0)
           strcat(buf, ",");

        if (sip_allow_api_conv(tmp, &allow->allowMethod[i], SIP_API_TO_STR) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "wrong allow method\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
        
        strcat(buf, tmp);
    }

    sprintf((char *)sipEncBuf, "Allow: %s\r\n", buf);

    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_subject(char *dest, SIP_HDR_SUBJECT *subject)
{
    if ((dest == NULL) || (subject == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_subject: dest or subject is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Subject: %s\r\n", subject->subject);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_server(char *dest, SIP_HDR_SERVER *server)
{
    if ((dest == NULL) || (server == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_server: dest or server is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Server: %s\r\n", server->server);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_user_agent(char *dest, SIP_HDR_USER_AGENT *userAgent)
{
    if ((dest == NULL) || (userAgent == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_user_agent: dest or userAgent is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "User-Agent: %s\r\n", userAgent->agent);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_supported(char *dest, SIP_HDR_SUPPORTED *supported)
{
    char        option[64];

    if ((dest == NULL) || (supported == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_supported: dest or supported is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_option_tag_api_conv(option, &supported->optionTag, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode supported option tag failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Supported: %s\r\n", option);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_mime_version(char *dest, SIP_HDR_MIME_VERSION *mimeVer)
{
    char        version[16];

    if ((dest == NULL) || (mimeVer == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_mime_version: dest or mimeVer is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_mime_version_api_conv(version, &mimeVer->mimeVersion, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode mime vesion failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Mime-Version: %s\r\n", version);

    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_date(char *dest, SIP_HDR_DATE *date)
{
    char     wkDay[32];
    char     month[32];
    char     dateType[16];

    if ((dest == NULL) || (date == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_date: dest or accept_encoding is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_date_weekday_api_conv(wkDay, &date->wkDay, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode date weekday failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_date_month_api_conv(month, &date->mon, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode date month failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_date_type_api_conv(dateType, &date->dateType, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode date type failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sprintf((char *)sipEncBuf, "Date: %s, %02d %s %ld %02d:%02d:%02d %s\r\n", wkDay, date->mDay, month, date->year, date->hour, date->min, date->sec, dateType);

    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_expires(char *dest, SIP_HDR_EXPIRES *expires)
{
    if ((dest == NULL) || (expires == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_expires: dest or expires is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Expires: %ld\r\n", expires->value);
    
    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_time_stamp(char *dest, SIP_HDR_TIMESTAMP *stamp) 
{
    if ((dest == NULL) || (stamp == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_time_stamp: dest or stamp is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf ((char *)sipEncBuf, "Timestamp: %ld\r\n", stamp->timeStamp);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_contacts(char *dest, SIP_HDR_CONTACTS *contacts)
{
    char                url[64];
    char                params[256];
    BYTE                i, head;
    SIP_HDR_CONTACT     *contact;

    if ((dest == NULL) || (contacts == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_contacts: dest or contacts is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((contacts->num == 0) || (contacts->num > SIP_MAX_NUM_OF_CONTACTS)) 
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_contacts: contacts num wrong\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    head = contacts->head;
    
    for (i = 0; i < contacts->num; i++, contact++)
    {
        contact = &contacts->contacts[head];

        sip_encode_url(url, &contact->url, SIP_ENCODE_URL_ALL);
        if (sip_encode_params(params, &contact->params, 0) < 0)
            sprintf((char *)sipEncBuf, "Contact: %s\r\n", url);
        else
            sprintf((char *)sipEncBuf, "Contact: %s;%s\r\n", url, params);
        
        strcat(dest, (char *)sipEncBuf);

        if (++head >= contacts->num)
            head = 0;
    }
    
    return 0;
}

int sip_encode_hdr_from(char *dest, SIP_HDR_FROM *from)
{
    char    url[64];
    char    params[256];

    if ((dest == NULL) || (from == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_from: dest or from is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_encode_url(url, &from->url, SIP_ENCODE_URL_ALL);
    if (sip_encode_params(params, &from->params, 0) < 0)
    {
        if (from->dispName[0] == '\0')
            sprintf((char *)sipEncBuf, "From: %s\r\n", url);
        else
            sprintf((char *)sipEncBuf, "From: %s %s\r\n", from->dispName, url);
    }
    else
    {
        if (from->dispName[0] == '\0')
            sprintf((char *)sipEncBuf, "From: %s;%s\r\n", url, params);
        else
            sprintf((char *)sipEncBuf, "From: %s %s;%s\r\n", from->dispName, url, params);
    }
    
    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_proxy_require(char *dest, SIP_HDR_PROXY_REQUIRE *proxyRequire)
{
    char        option[64];

    if ((dest == NULL) || (proxyRequire == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_proxy_require: dest or proxyRequire is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_option_tag_api_conv(option, &proxyRequire->optionTag, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode proxy require option tag failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Proxy-Require: %s\r\n", option);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_to(char *dest, SIP_HDR_TO *to)
{
    char    url[256];
    char    params[256];

    if ((dest == NULL) || (to == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_to: dest or to is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
 
    sip_encode_url(url, &to->url, SIP_ENCODE_URL_ALL);

    if (sip_encode_params(params, &to->params, 0) < 0)
    {
        if (to->dispName[0] == '\0')
            sprintf((char *)sipEncBuf, "To: %s\r\n", url);
        else
            sprintf((char *)sipEncBuf, "To: %s %s\r\n", to->dispName, url);
    }
    else
    {
        if (to->dispName[0] == '\0')
            sprintf((char *)sipEncBuf, "To: %s;%s\r\n", url, params);
        else
            sprintf((char *)sipEncBuf, "To: %s %s;%s\r\n", to->dispName, url, params);
    }
        
    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_encode_hdr_record_routes(char *dest, SIP_HDR_RECORD_ROUTES *recRoutes)
{
    BYTE    i, head;
    char        url[64];
    SIP_HDR_RECORD_ROUTE    *recRoute;

    if ((dest == NULL) || (recRoutes == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_record_routes: dest or recRoutes is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if ((recRoutes->num == 0) || (recRoutes->num > SIP_MAX_NUM_OF_RECORD_ROUTES))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_record_routes: record routes num wrong\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    head = recRoutes->head;
    
    for (i = 0; i < recRoutes->num; i++, recRoute++)
    {
        recRoute = &recRoutes->recRoutes[head];

        sip_encode_url(url, &recRoute->url, SIP_ENCODE_URL_NO_USER_PART);
        sprintf((char *)sipEncBuf, "Record-Route: %s\r\n", url);
        
        strcat(dest, (char *)sipEncBuf);

        if (++head >= recRoutes->num)
            head = 0;
    }
    
    return 0;
}

int sip_encode_hdr_require(char *dest, SIP_HDR_REQUIRE *require)
{
    char        option[64];

    if ((dest == NULL) || (require == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_require: dest or require is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_option_tag_api_conv(option, &require->optionTag, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode require option tag failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Require: %s\r\n", option);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_routes(char *dest, SIP_HDR_ROUTES *routes)
{
    BYTE                    i, head;
    char                    url[64];
    SIP_HDR_ROUTE           *route;

    if ((dest == NULL) || (routes == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_routes: dest or routes is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((routes->num == 0) || (routes->num > SIP_MAX_NUM_OF_ROUTES))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_routes: routes num wrong\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    head = routes->head;
    
    for (i = 0; i < routes->num; i++)
    {
        route = &routes->routes[head];

        sip_encode_url(url, &route->url, SIP_ENCODE_URL_ALL);//SIP_ENCODE_URL_NO_USER_PART
        sprintf((char *)sipEncBuf, "Route: %s\r\n", url);
        
        strcat(dest, (char *)sipEncBuf);

        if (++head >= SIP_MAX_NUM_OF_ROUTES)
            head = 0;
    }
    
    return 0;
}

int sip_encode_hdr_unsupported(char *dest, SIP_HDR_UNSUPPORTED *unsupported)
{
    char        option[64];

    if ((dest == NULL) || (unsupported == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_unsupported: dest or unsupported is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_option_tag_api_conv(option, &unsupported->optionTag, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode unsupported option tag failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Unsupported: %s\r\n", option);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_vias(char *dest, SIP_HDR_VIAS *vias)
{
    BYTE        i, head, count = 0;
    char        ver[8], proto[8];
    char        url[128],params[256];
    SIP_HDR_VIA *via;

    if ((dest == NULL) || (vias == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_vias: dest or vias is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((vias->num == 0) || (vias->num > SIP_MAX_NUM_OF_VIAS)) 
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_vias: vias num wrong\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    head = vias->head;
    
    for (i = 0; i < SIP_MAX_NUM_OF_VIAS; i++, via++)
    {
        via = &vias->vias[head];

        if (via->version == 0)
        {
            if (++head >= vias->num)
                head = 0;

            if (++count >= vias->num)
                break;

            continue;
        }
        
        if (sip_ver_api_conv(ver, &via->version, SIP_API_TO_STR) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "encode via version failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
        
        if (sip_proto_api_conv(proto, &via->protocol, SIP_API_TO_STR) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "encode via protocal failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
        
        sip_encode_via_url(url, &via->url, SIP_ENCODE_URL_NO_USER_PART | SIP_ENCODE_URL_NO_BRACKETS);

        if (sip_encode_params(params, &via->params, 0) < 0)
            sprintf((char *)sipEncBuf, "Via: %s/%s %s\r\n", ver, proto, url);
        else
            sprintf((char *)sipEncBuf, "Via: %s/%s %s;%s\r\n", ver, proto, url, params);
        
        strcat(dest, (char *)sipEncBuf);

        if (++head >= vias->num)
            head = 0;

        if (++count >= vias->num)
            break;
    }
    
    return 0;
}

int sip_encode_hdr_max_forwards(char *dest, SIP_HDR_MAX_FORWARDS *maxForwards)
{
    if ((dest == NULL) || (maxForwards == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_max_forwards: dest or maxForwards is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Max-Forwards: %d\r\n", maxForwards->value);
        
    strcat(dest, (char *)sipEncBuf);
    
    return 0;
}

int sip_transport_encode_headers(char *dest, SIP_API_STRUCT *sipApiMsg)
{
    SIP_MSG *sipMsg;

    if ((dest == NULL) || (sipApiMsg == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: dest or sipApiMsg is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sipMsg = &sipApiMsg->sipApiMsg.sipMsg;

    // General headers encoding
    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_VIA_MASK) == 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: sip api without Via header\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_hdr_vias(dest, &sipMsg->sipHdrVias) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Via header failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_TO_MASK) == 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: sip api without To header\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if (sip_encode_hdr_to(dest, &sipMsg->sipHdrTo) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers:encode To header failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_FROM_MASK) == 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: sip api without From header\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if (sip_encode_hdr_from(dest, &sipMsg->sipHdrFrom) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers:encode From header failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_CALL_ID_MASK) == 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: sip api without Call-ID header\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_hdr_call_id(dest, &sipMsg->sipHdrCallId) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers:encode Call-ID header failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_CSEQ_MASK) == 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: sip api without Cseq header\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_hdr_cseq(dest, &sipMsg->sipHdrCseq) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Cseq header failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_CONTACT_MASK) == SIP_HDR_CONTACT_MASK)
    {
        if (sip_encode_hdr_contacts(dest, &sipMsg->sipHdrContacts) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Contact header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }


    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_ALLOW_MASK) == SIP_HDR_ALLOW_MASK)
    {
        if (sip_encode_hdr_allow(dest, &sipMsg->sipHdrAllow) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode allow header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_SUPPORTED_MASK) == SIP_HDR_SUPPORTED_MASK)
    {
        if (sip_encode_hdr_supported(dest, &sipMsg->sipHdrSupported) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Supported header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_ACCEPT_MASK) == SIP_HDR_ACCEPT_MASK)
    {
        if (sip_encode_hdr_accept(dest, &sipMsg->sipHdrAccept) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Accept header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_ACCEPT_ENCODING_MASK) == SIP_HDR_ACCEPT_ENCODING_MASK)
    {
        if (sip_encode_hdr_accept_encoding(dest, &sipMsg->sipHdrAcceptEncoding) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Accept-Encoding header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_ACCEPT_LANGUAGE_MASK) == SIP_HDR_ACCEPT_LANGUAGE_MASK)
    {
        if (sip_encode_hdr_accept_language(dest, &sipMsg->sipHdrAcceptLanguage) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode accept-language header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_TIMESTAMP_MASK) == SIP_HDR_TIMESTAMP_MASK)
    {
        if (sip_encode_hdr_time_stamp(dest, &sipMsg->sipHdrStamp) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Timestamp header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_MIME_VERSION_MASK) == SIP_HDR_MIME_VERSION_MASK)
    {
        if (sip_encode_hdr_mime_version(dest, &sipMsg->sipHdrMimeVer) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Mime-Version header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_DATE_MASK) == SIP_HDR_DATE_MASK)
    {
        if (sip_encode_hdr_date(dest, &sipMsg->sipHdrDate) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Date header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }
    
    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_EXPIRES_MASK) == SIP_HDR_EXPIRES_MASK)
    {
        if (sip_encode_hdr_expires(dest, &sipMsg->sipHdrExpires) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Expires header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }
    
    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_RECORD_ROUTE_MASK) == SIP_HDR_RECORD_ROUTE_MASK)
    {
        if (sip_encode_hdr_record_routes(dest, &sipMsg->sipHdrRecordRoutes) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Record-Route header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((sipMsg->sipGenHdrFlag[0] & SIP_HDR_USER_AGENT_MASK) == SIP_HDR_USER_AGENT_MASK)
    {
        if (sip_encode_hdr_user_agent(dest, &sipMsg->sipHdrUserAgent) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Agent header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }
    
    if (sipApiMsg->sipApiType == SIP_API_RES_MSG)
    {
        // Response headers encoding    
        if ((sipMsg->sipReStruct.sipReHdrFlag[0] & SIP_HDR_SERVER_MASK) == SIP_HDR_SERVER_MASK)
        {
            if (sip_encode_hdr_server(dest, &sipMsg->sipReStruct.sipReHdr.sipRspHdr.sipHdrServer) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Server header failed\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        if ((sipMsg->sipReStruct.sipReHdrFlag[0] & SIP_HDR_UNSUPPORTED_MASK) == SIP_HDR_UNSUPPORTED_MASK)
        {
            if (sip_encode_hdr_unsupported(dest, &sipMsg->sipReStruct.sipReHdr.sipRspHdr.sipHdrUnsupported) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Unsupported header failed\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }    
    }
    else
    {
        // Request headers encoding
        if ((sipMsg->sipReStruct.sipReHdrFlag[0] & SIP_HDR_MAX_FORWARDS_MASK) == 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: sip request api without Max-Forwards header\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        if (sip_encode_hdr_max_forwards(dest, &sipMsg->sipReStruct.sipReHdr.sipReqHdr.sipHdrMaxForwards) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Max-Forwards header failed\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
        
        if ((sipMsg->sipReStruct.sipReHdrFlag[0] & SIP_HDR_ROUTE_MASK) == SIP_HDR_ROUTE_MASK)
        {
            if (sip_encode_hdr_routes(dest, &sipMsg->sipReStruct.sipReHdr.sipReqHdr.sipHdrRoutes) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Route header failed\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        if ((sipMsg->sipReStruct.sipReHdrFlag[0] & SIP_HDR_REQUIRE_MASK) == SIP_HDR_REQUIRE_MASK)
        {
            if (sip_encode_hdr_require(dest, &sipMsg->sipReStruct.sipReHdr.sipReqHdr.sipHdrRequire) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Require header failed\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        if ((sipMsg->sipReStruct.sipReHdrFlag[0] & SIP_HDR_PROXY_REQUIRE_MASK) == SIP_HDR_PROXY_REQUIRE_MASK)
        {
            if (sip_encode_hdr_proxy_require(dest, &sipMsg->sipReStruct.sipReHdr.sipReqHdr.sipHdrProxyRequire) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Proxy-Require header failed\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        if ((sipMsg->sipReStruct.sipReHdrFlag[0] & SIP_HDR_SUBJECT_MASK) == SIP_HDR_SUBJECT_MASK)
        {
            if (sip_encode_hdr_subject(dest, &sipMsg->sipReStruct.sipReHdr.sipReqHdr.sipHdrSubject) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "sip_transport_encode_headers: encode Subject header failed\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }
    }
    
    return 0;
}

int sip_encode_hdr_content_disposition(char *dest, SIP_CONTENT_DISPOSITION *sipBodyContentDisposition)
{
    char        disposition[32];
    char        params[64];

    if ((dest == NULL) || (sipBodyContentDisposition == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_content_disposition: dest or sipBodyContentDisposition is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_content_disposition_api_conv(disposition,  &sipBodyContentDisposition->contentDisposition, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode Content-Disposition failed\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_params(params, &sipBodyContentDisposition->params, 0) < 0)
    {
        sprintf((char *)sipEncBuf, "Content-Disposition: %s\r\n", disposition);
    }
    else
    {
        sprintf((char *)sipEncBuf, "Content-Disposition: %s;%s\r\n", disposition, params);
    }

    strcat(dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_content_encoding(char *dest, BYTE *sipContentEncoding)
{
    char        tmp[32];

    if ((dest == NULL) || (sipContentEncoding == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_content_encoding: dest or sipContentEncoding is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_content_encoding_api_conv(tmp, sipContentEncoding, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode Content-Encoding failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf ((char *)sipEncBuf, "Content-Encoding: %s\r\n", tmp);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_hdr_content_language(char *dest, BYTE *sipContentLanguage)
{
    char        tmp[32];

    if ((dest == NULL) || (sipContentLanguage == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_hdr_content_language: dest or sipContentLanguage is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_content_language_api_conv(tmp, sipContentLanguage, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode Content-Language failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sprintf((char *)sipEncBuf, "Content-Language: %s\r\n", tmp);

    strcat (dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_sub_body_hdr_content_type(char *dest, SIP_CONTENT_TYPE *sipBodyContentType)
{
    char        type[32];
    char        subType[32];
    char        params[64];

    if ((dest == NULL) || (sipBodyContentType == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_sub_body_hdr_content_type: dest or sipBodyContentType is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_content_type_api_conv(type, &sipBodyContentType->type, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode sub Content-Type failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_content_sub_type_api_conv(subType,  &sipBodyContentType->subType, SIP_API_TO_STR) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "encode sub Content-Type subType failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (sip_encode_params(params, &sipBodyContentType->params, 0) < 0)
    {
        sprintf((char *)sipEncBuf, "Content-Type: %s/%s\r\n", type, subType);
    }
    else
    {
        sprintf((char *)sipEncBuf, "Content-Type: %s/%s;%s\r\n", type, subType, params);
    }

    strcat(dest, (char *)sipEncBuf);

    return 0;
}

int sip_encode_sub_body(char *dest, SIP_MSG sipMsg, SIP_MESSAGE_BODYS sipBodys)
{
    int         i;
    char        boundary[32];

    if (dest == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_sub_body: dest is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    for (i = 0; i < sipMsg.sipEntity.sipHdrContentType.params.paraNum; i++)
    {
        if (sipMsg.sipEntity.sipHdrContentType.params.para[i].paraName== SIP_API_PNAME_BOUNDARY)
        {
            sprintf(boundary, "--%s", sipMsg.sipEntity.sipHdrContentType.params.para[i].para.paraStr);
            break;
        }
    }

    if (i == sipMsg.sipEntity.sipHdrContentType.params.paraNum)
    {
        sprintf((char *)sipAsciTempBuf, "sip_encode_sub_body:encode sub boundary failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    for (i = 0; i < sipBodys.sipBodyNum; i++)
    {
        if ((sipBodys.sipBody[i].sipBodyHdrFlg[0] & SIP_HDR_CONTENT_TYPE_MASK) == 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_encode_sub_body:no content type flag\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        if (((sipBodys.sipBody[i].sipBodyHdrFlg[0] & SIP_HDR_CONTENT_DISPOSITION_MASK) == 0) 
             && (sipBodys.sipBody[i].sipBodyContentType.subType == SIP_CONTENT_SUB_TYPE_ISUP))
        {
            sprintf((char *)sipAsciTempBuf, "isup sub body without disposition\r\n");
            sip_log_err(sipAsciTempBuf);
            return -2;
        }

        strcat (dest, boundary);

        strcat (dest, "\r\n");

        if ((sipBodys.sipBody[i].sipBodyHdrFlg[0] & SIP_HDR_CONTENT_DISPOSITION_MASK) == SIP_HDR_CONTENT_DISPOSITION_MASK)
        {
            sip_encode_hdr_content_disposition(dest, &sipBodys.sipBody[i].sipBodyContentDisposition);
        }

        sip_encode_sub_body_hdr_content_type(dest, &sipBodys.sipBody[i].sipBodyContentType);

        strcat (dest, "\r\n");

        strcat (dest, (char *)sipBodys.sipBody[i].msgBody);

        if (i < sipBodys.sipBodyNum -1)
            strcat (dest, "\r\n\r\n");
        else
            strcat(dest, "\r\n");
    }

    strcat (dest, boundary);
    strcat (dest, "--\r\n");

    return 0;
}

int sip_encode_body(char *dest, SIP_MSG sipMsg, SIP_MESSAGE_BODYS sipBodys)
{
    char        buffer[SIP_MAX_BODY_LEN] = "";

    switch (sipMsg.sipEntity.sipHdrContentType.subType)
    {
    case SIP_CONTENT_SUB_TYPE_MIXED:
        if (sip_encode_sub_body(buffer, sipMsg, sipBodys) < 0)
            return -1;
              
        strcat(dest, buffer);
        break;

    default :
        strcat(dest, (char *)sipBodys.sipBody[0].msgBody);
        break;
    }

    return 0;
    
}

int sip_transport_encode_body(char *dest, SIP_API_STRUCT *sipApiMsg)
{
    char        type[32];
    char        subType[32];
    char        params[64];
    
    SIP_ENTITY  *sipEntity;

    if ((dest ==NULL) || (sipApiMsg == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_transport_encode_body: dest or sipApiMsg is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sipEntity = &sipApiMsg->sipApiMsg.sipMsg.sipEntity;

    if (sipEntity->sipHdrContentLength > 0)
    {
        if (sip_content_type_api_conv(type, &sipEntity->sipHdrContentType.type, SIP_API_TO_STR) < 0)
            return -1;
        if (sip_content_sub_type_api_conv(subType, &sipEntity->sipHdrContentType.subType, SIP_API_TO_STR) < 0)
            return -1;

        if (sip_encode_params(params, &sipEntity->sipHdrContentType.params, 0) < 0)
        {
            sprintf((char *)sipEncBuf, "Content-Type: %s/%s\r\n", type, subType);
        }
        else
        {
            sprintf((char *)sipEncBuf, "Content-Type: %s/%s;%s\r\n", type, subType, params);
        }

        strcat(dest, (char *)sipEncBuf);

        if ((sipEntity->sipEntityHdrFlag[0] & SIP_HDR_CONTENT_DISPOSITION_MASK) == SIP_HDR_CONTENT_DISPOSITION_MASK)
        {
            if (sip_encode_hdr_content_disposition(dest, &sipEntity->sipHdrContentDisposition) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "wrong content disposition\r\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        if ((sipEntity->sipEntityHdrFlag[0] & SIP_HDR_CONTENT_ENCODING_MASK) == SIP_HDR_CONTENT_ENCODING_MASK)
        {
            if (sip_encode_hdr_content_encoding(dest, &sipEntity->sipHdrContentEncoding) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "wrong content encoding\r\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        if ((sipEntity->sipEntityHdrFlag[0] & SIP_HDR_CONTENT_LANGUAGE_MASK) == SIP_HDR_CONTENT_LANGUAGE_MASK)
        {
            if (sip_encode_hdr_content_language(dest, &sipEntity->sipHdrContentLanguage) < 0)
            {
                sprintf((char *)sipAsciTempBuf, "wrong content language\r\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        sprintf((char *)sipEncBuf, "Content-Length: %d\r\n\r\n", sipEntity->sipHdrContentLength);
    }
    else
        sprintf((char *)sipEncBuf, "Content-Length: %d\r\n\r\n", sipEntity->sipHdrContentLength);

    strcat(dest, (char *)sipEncBuf);
    
    if (sipEntity->sipHdrContentLength > 0)
    {
        sip_encode_body(dest, sipApiMsg->sipApiMsg.sipMsg, sipEntity->sipBodys);
    }
    
    return 0;
}

int sip_transport_set_addr(struct sockaddr_in *dstAddr, SIP_API_STRUCT *sipApiMsg)
{
    SIP_TRANSPORT_ADDR *sipTransAddr = &sipApiMsg->sipTransAddr;

    memset(dstAddr, 0, sizeof(struct sockaddr));
    dstAddr->sin_family = AF_INET;
    dstAddr->sin_port = htons(sipTransAddr->port);
    dstAddr->sin_addr.s_addr = sipTransAddr->addr.ipV4;
    memset(&(dstAddr->sin_zero), 0, 8);
    
    return 0;
}

int sip_transport_set_sd_addr(struct sockaddr_in *dstAddr, SIP_TRANSPORT_ADDR *sipTransAddr)
{
    memset(dstAddr, 0, sizeof(struct sockaddr));
    dstAddr->sin_family = AF_INET;
    dstAddr->sin_port = htons(sipTransAddr->port);
    dstAddr->sin_addr.s_addr = sipTransAddr->addr.ipV4;
    memset(&(dstAddr->sin_zero), 0, 8);
    
    return 0;
}
