#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_debug.h"

// Utility code start

char *sip_strncpy(char *dest, const char *src, WORD length)
{
    if ((dest == NULL) || (src == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_strncpy: dest or src is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return NULL;
    }

    strncpy(dest, src, length);
    dest[length] = '\0';
    return dest;
}

// remove SPACE before and after the content
int sip_clrspace(char *word)
{
    char *pbeg;
    char *pend;
    WORD len;

    if (word == NULL)
        return -1;
    if (*word == '\0')
        return 0;
    len = strlen (word);

    pbeg = word;
    while ((' ' == *pbeg) || ('\r' == *pbeg) || ('\n' == *pbeg) || ('\t' == *pbeg))
        pbeg++;

    pend = word + len - 1;
    while ((' ' == *pend) || ('\r' == *pend) || ('\n' == *pend) || ('\t' == *pend))
    {
        pend--;
        if (pend < pbeg)
        {
            *word = '\0';
            return 0;
        }
    }

    // Add terminating NULL only if we've cleared room for it
    if (pend + 1 <= word + (len - 1))
        pend[1] = '\0';

    if (pbeg != word)
        memcpy(word, pbeg, pend - pbeg + 2);

    return 0;
}

char *sip_clrncpy(char *dst, char *src, WORD len)
{
    char *pbeg;
    char *pend;
    char *p;
    WORD spaceless_length;

    if ((dst == NULL) || (src == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_clrncpy: dst or src is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return NULL;
    }

    // find the start of relevant text
    pbeg = src;
    while ((' ' == *pbeg) || ('\r' == *pbeg) || ('\n' == *pbeg) || ('\t' == *pbeg))
        pbeg++;

    // find the end of relevant text
    pend = src + len - 1;
    while ((' ' == *pend) || ('\r' == *pend) || ('\n' == *pend) || ('\t' == *pend))
    {
        pend--;
        if (pend < pbeg)
        {
            *dst = '\0';
            return dst;
        }
    }

    // if pend == pbeg there is only one char to copy
    spaceless_length = pend - pbeg + 1;   // excluding any '\0'
    memcpy(dst, pbeg, spaceless_length);
    p = dst + spaceless_length;

    // terminate the string and pad dest with zeros until len
    do
    {
        *p = '\0';
        p++;
        spaceless_length++;
    }
    while (spaceless_length < len);

    return dst;
}

int sip_set_next_token(char *dest, char *buf, int endSeparator, char **next)
{
    char *sep;                      // separator

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

    *next = NULL;

    sep = buf;
    while ((*sep != endSeparator) && (*sep != '\0') && (*sep != '\r')
         && (*sep != '\n'))
        sep++;
    if ((*sep == '\r') || (*sep == '\n'))
    {                               // we should continue normally only if this is the separator asked!
        if (*sep != endSeparator)
            return -1;
    }
    if (*sep == '\0')
        return -1;                  // value must not end with this separator!
    if (sep == buf)
        return -1;                  // empty value (or several space!)

    sip_strncpy(dest, buf, sep - buf);

    *next = sep + 1;                // return the position right after the separator
    
    return 0;
}

void sip_util_replace_all_lws(char *msg)
{
    char *tmp;

    if (msg == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_util_replace_all_lws: msg is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return;
    }

    tmp = msg;
    
    for (; tmp[0] != '\0'; tmp++)
    {
        if (('\0' == tmp[0]) || ('\0' == tmp[1])    ||
            ('\0' == tmp[2]) || ('\0' == tmp[3]))
            return;

        if ((('\r' == tmp[0]) && ('\n' == tmp[1])   &&
             ('\r' == tmp[2]) && ('\n' == tmp[3]))  ||
            (('\r' == tmp[0]) && ('\r' == tmp[1]))  ||
            (('\n' == tmp[0]) && ('\n' == tmp[1])))
            return;

        if ((('\r' == tmp[0]) && ('\n' == tmp[1])   &&
            ((' ' == tmp[2]) || ('\t' == tmp[2])))  ||
            (('\r' == tmp[0]) && 
            ((' ' == tmp[1]) || ('\t' == tmp[1])))  ||
            (('\n' == tmp[0]) &&
            ((' ' == tmp[1]) || ('\t' == tmp[1]))))
        {
            // Replace line end and TAB symbols by SP
            tmp[0] = ' ';
            tmp[1] = ' ';
            tmp = tmp + 2;
            // Replace all following TAB symbols
            for (; ('\t' == tmp[0] || ' ' == tmp[0]); )
            {
                tmp[0] = ' ';
                tmp++;
            }
        }
    }
}

// this method search for the separator and
// return it only if it is located before the
// second separator
char *sip_next_separator(char *ch, int separatorToFind, int beforeSeparator)
{
    char *ind;
    char *tmp;

    if (ch == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_next_separator: ch is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return NULL;
    }

    ind = strchr (ch, separatorToFind);
    if (ind == NULL)
        return NULL;

    tmp = NULL;
    if (beforeSeparator != 0)
        tmp = strchr(ch, beforeSeparator);

    if (tmp != NULL)
    {
        if (ind < tmp)
            return ind;
    }
    else
        return ind;

    return NULL;
}

void sip_uri_unescape(char *string)
{
    int alloc = strlen (string) + 1;
    unsigned char in;
    int index = 0;
    unsigned int hex;
    char *ptr;

    if (string == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_uri_unescape: string is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return;
    }

    ptr = string;
    while (--alloc > 0)
    {
        in = *ptr;
        if ('%' == in)
        {
            // encoded part
            if (sscanf (ptr + 1, "%02X", &hex) == 1)
            {
                in = (unsigned char) hex;
                if (*(ptr + 2) &&
                    ((*(ptr + 2) >= '0' && *(ptr + 2) <= '9') ||
                    (*(ptr + 2) >= 'a' && *(ptr + 2) <= 'f') ||
                    (*(ptr + 2) >= 'A' && *(ptr + 2) <= 'F')))
                {
                    alloc -= 2;
                    ptr += 2;
                }
                else
                {
                    alloc -= 1;
                    ptr += 1;
                }
            }
        }
        string[index++] = in;
        ptr++;
    }
    string[index] = 0;            // terminate it
}

// in quoted-string, many characters can be escaped...
// sip_quote_find returns the next quote that is not escaped
char *sip_quote_find(char *qstring)
{
    char    *quote;
    int     i = 1;

    if (qstring == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_quote_find: qstring is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return NULL;
    }

    quote = strchr(qstring, '"');
    if (quote == qstring)           // the first char matches and is not escaped...
        return quote;

    if (quote == NULL)
        return NULL;                // no quote at all...

    /* this is now the nasty cases where '"' is escaped
     '" jonathan ros \\\""'
     |                  |
     '" jonathan ros \\"'
     |                |
     '" jonathan ros \""'
     |                |
     we must count the number of preceeding '\' */

    for (;;)
    {
        if (0 == strncmp(quote - i, "\\", 1))
            i++;
        else
        {
            if (i % 2 == 1)         // the '"' was not escaped
                return quote;

            // else continue with the next '"'
            quote = strchr (quote + 1, '"');
            if (quote == NULL)
                return NULL;
            i = 1;
        }
        if (quote - i == qstring - 1)
          // example: "\"john"
          // example: "\\"jack"
        {
            // special case where the string start with '\'
            if (*qstring == '\\')
                i++;                // an escape char was not counted
            if (i % 2 == 0)         // the '"' was not escaped
                return quote;
            else
            {                       // else continue with the next '"'
                qstring = quote + 1;    // reset qstring because
                                        //   (*quote+1) may be also == to '\\'
                quote = strchr(quote + 1, '"');
                if (quote == NULL)
                    return NULL;
                i = 1;
            }
        }
    }
    
    return NULL;
}

int sip_uri_param_set(SIP_GEN_PARA *urlParam, char *pname, char *pvalue)
{
    BYTE flag = 0;

    if ((urlParam == NULL) || (pname == NULL) || (pvalue == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_uri_param_set: urlParm pname or pvalue is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrspace(pname);
    sip_clrspace(pvalue);
    
    if (strcmp(pname, SIP_PNAME_TAG) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_TAG;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;
    }
    else if (strcmp(pname, SIP_PNAME_BRANCH) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_BRANCH;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;
    }
    else if (strcmp(pname, SIP_PNAME_EXPIRES) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_EXPIRES;
        urlParam->paraType = flag = SIP_API_PTYPE_VALUE;
        urlParam->para.paraVal[0] = atol(pvalue);
    }
    else if (strcasecmp(pname, SIP_PNAME_USER) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_USER;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;
    }
    else if (strcmp(pname, SIP_PNAME_LR) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_LR;
        urlParam->paraType = flag = SIP_API_PTYPE_TAG;
    }
    else if (strcmp(pname, SIP_PNAME_BOUNDARY) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_BOUNDARY;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;
    }
    else if (strcmp(pname, SIP_PNAME_HANDLING) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_HANDLING;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;       
    }
    else if (strcmp(pname, SIP_PNAME_TRANSPORT) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_TRANSPORT;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;           
    }
    else if (strcmp(pname, SIP_PNAME_RPORT) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_RPOTR;
        urlParam->paraType = flag = SIP_API_PTYPE_VALUE;
        if (pvalue[0] == '\0')
            urlParam->para.paraVal[0] = 0xFFFFFFFF;
        else
            urlParam->para.paraVal[0] = atol(pvalue);
    }
    else if (strcmp(pname, SIP_PNAME_VERSION) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_VERSION;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;       
    }
    else if (strcmp(pname, SIP_PNAME_BASE) == 0)
    {
        urlParam->paraName = SIP_API_PNAME_BASE;
        urlParam->paraType = flag = SIP_API_PTYPE_STRING;       
    }
    
    if (flag)
    {
        if (flag == SIP_API_PTYPE_STRING)
            strcpy(urlParam->para.paraStr, pvalue);
        return 0;
    }
    
    return -1;
}

int sip_uri_param_add(SIP_GEN_PARAMS *urlParams, char *pname, char *pvalue)
{
    SIP_GEN_PARA    *urlParam;

    if ((urlParams == NULL) || (pname == NULL) || (pvalue == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_uri_param_add: urlParms pname or pvalue is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (urlParams->paraNum > SIP_MAX_PARA_NUM)
        return -1;
    
    urlParam = &urlParams->para[urlParams->paraNum];
    
    if (sip_uri_param_set(urlParam, pname, pvalue) < 0)
        return -1;
    
    urlParams->paraNum++;
    
    return 0;
}

int sip_uri_parse_params(SIP_URI *sipUri, char *params)
{
    char pname[64];
    char pvalue[128];

    char *comma;
    char *equal;

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

    // find '=' which is the separator for one param
    // find ';' which is the separator for multiple params

    equal = sip_next_separator(params + 1, '=', ';');
    comma = strchr(params + 1, ';');

    while (comma != NULL)
       {
            if (equal == NULL)
           {
               equal = comma;
             pvalue[0] = '\0';
            }
            else
           {
               if ((comma - equal < 2) || (comma - equal > 128))
             {
                   sprintf((char *)sipAsciTempBuf, "uri param value length out of range\r\n");
                   sip_log_err(sipAsciTempBuf);
                     return -1;
             }

             sip_strncpy(pvalue, equal + 1, comma - equal - 1);
             sip_uri_unescape(pvalue);
           }

            if ((equal - params < 2) || (equal - params > 64))
           {
               sprintf((char *)sipAsciTempBuf, "uri param name length out of range\r\n");
               sip_log_err(sipAsciTempBuf);
               return -1;
           }

            sip_strncpy(pname, params + 1, equal - params - 1);
            sip_uri_unescape(pname);

            sip_uri_uparam_add(sipUri, pname, pvalue);

            params = comma;
            equal = sip_next_separator(params + 1, '=', ';');
            comma = strchr(params + 1, ';');    
       }

    // this is the last header (comma==NULL)
    comma = params + strlen (params);

    if (equal == NULL)
       {
            equal = comma;            /* at the end */
            pvalue[0] = '\0';
    }
    else
       {
            if ((comma - equal < 2) || (comma - equal > 128))
            {
               sprintf((char *)sipAsciTempBuf, "uri last param value length out of range\r\n");
               sip_log_err(sipAsciTempBuf);
               return -1;
            }

            sip_strncpy(pvalue, equal + 1, comma - equal - 1);
       }

    if ((equal - params < 2) || (equal - params > 64))
    {
           sprintf((char *)sipAsciTempBuf, "uri last param name length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip_strncpy(pname, params + 1, equal - params - 1);

    sip_uri_uparam_add(sipUri, pname, pvalue);

    return 0;
}

int sip_generic_param_parseall(SIP_GEN_PARAMS *genParams, char *params)
{
    char pname[32];
    char pvalue[64];
    char *comma;
    char *equal;
    char *tmp;

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

    // find '=' which is the separator for one param
    // find ';' which is the separator for multiple params

    equal = sip_next_separator(params + 1, '=', ';');
    comma = strchr(params + 1, ';');

    while (comma != NULL)
       {
           if (equal == NULL)
           {
               equal = comma;
             pvalue[0] = '\0';
            }
            else
           {
            // check for NULL param with an '=' character
            tmp = equal + 1;

        for (; *tmp == '\t' || *tmp == ' '; tmp++)
                {
                }
        
            pvalue[0] = '\0';

        if ((*tmp != ',') && (*tmp != '\0'))
                {
                if ((comma - equal < 2) || (comma - equal > 64))//comma - equal >128
                {
                         sprintf((char *)sipAsciTempBuf, "param value length out of range\r\n");
                         sip_log_err(sipAsciTempBuf);
                        return -1;
                }

                sip_clrncpy(pvalue, equal + 1, comma - equal - 1);
                }
          }

        if ((equal - params < 2) || (equal - params > 32))
        {
              sprintf((char *)sipAsciTempBuf, "param name length out of range\r\n");
              sip_log_err(sipAsciTempBuf);
            return -1;
        }
        
        sip_clrncpy(pname, params + 1, equal - params - 1);

        sip_generic_param_add(genParams, pname, pvalue);

        params = comma;
        
        equal = sip_next_separator(params + 1, '=', ';');
        comma = strchr(params + 1, ';');
    }

    // this is the last header (comma==NULL)
    comma = params + strlen (params);

    if (equal == NULL)
    {
        equal = comma;            /* at the end */
        pvalue[0] = '\0';
    }
    else
    {
        // check for NULL param with an '=' character
        tmp = equal + 1;

        for (; *tmp == '\t' || *tmp == ' '; tmp++)
         {
         }
    
         pvalue[0] = '\0';
        
         if (*tmp != ',' && *tmp != '\0')
        {
            if ((comma - equal < 2) || (comma - equal > 64))//comma - equal >128
            {
                sprintf((char *)sipAsciTempBuf, "last param value length out of range\r\n");
                sip_log_err(sipAsciTempBuf);
                  return -1;
            }

            sip_clrncpy(pvalue, equal + 1, comma - equal - 1);
        }
    }

    if ((equal - params < 2) || (equal - params > 32))
    {
        sprintf((char *)sipAsciTempBuf, "last param name length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
         return -1;
    }

    sip_clrncpy(pname, params + 1, equal - params - 1);

    sip_generic_param_add(genParams, pname, pvalue);

    return 0;
}

// Parse code start

int sip_uri_parse(SIP_URI *sipUri, char *buf)
{
    char    *userName;
    char    *password;
    char    *host;
    char    *port;
    char    *params;
    char    *headers;
    char    *tmp;
    char    temp[128];
    BYTE    len;
    
    // basic tests
    if ((sipUri == NULL) || (buf == NULL) || (buf[0] == '\0'))
    {
        sprintf((char *)sipAsciTempBuf, "sip_uri_parse: sipUri or buf is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    tmp = strchr(buf, ':');
    if (tmp == NULL)
        return -1;
    
    len = tmp - buf;

    if ((len < 2) || (len > 128))
    {
           sprintf((char *)sipAsciTempBuf, "uri type length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
            return -1;
    }
    
    sip_clrncpy(temp, buf, len);
    if (sip_uri_type_api_conv(temp, &sipUri->uriType, SIP_STR_TO_API) < 0)
        return -1;
    
    /*  law number 1:
        if ('?' exists && is_located_after '@')
        or   if ('?' exists && '@' is not there -no userName-)
        =====>  HEADER_PARAM EXIST
        =====>  start at index(?)
        =====>  end at the end of url
    */

    // find the beginning of host
    userName = strchr(tmp, ':');//userName = strchr(buf, ':');
    // if ':' does not exist, the url is not valid
    if (userName == NULL)
        return -1;

    host = strchr(tmp, '@');//host = strchr(buf, '@');

    if (host == NULL)
        host = userName;
    else if (userName[1] == '@')  // userName is empty
        host = userName + 1;
    else
    {   // userName exists
        password = sip_next_separator(userName + 1, ':', '@');

        if (password == NULL)
            password = host;
        else
        {   // password exists
            if ((host - password < 2) || (host - password > 16))
            {
                  sprintf((char *)sipAsciTempBuf, "password length out of range\r\n");
                  sip_log_err(sipAsciTempBuf);
                    return -1;
            }

            sip_clrncpy(sipUri->password, password + 1, host - password - 1);
            sip_uri_unescape(sipUri->password);
        }
        
        if ((password - userName < 2) || (password - userName > 64))//password - userName > 128
       {
           sprintf((char *)sipAsciTempBuf, "uri userName length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
           return -1;
       }
              
        sip_clrncpy(sipUri->userName, userName + 1, password - userName - 1);
        sip_uri_unescape(sipUri->userName);
    }
    
    // search for header after host
    headers = strchr (host, '?');

    if (headers == NULL)
        headers = buf + strlen(buf);
    else
    {
        // headers exist
        // sip_uri_parse_headers(url, headers);
    }
    
    // search for params after host
    params = strchr(host, ';');  /* search for params after host */
    if (params == NULL)
        params = headers;
    else
    {   /* params exist */
        if ((headers - params + 1 < 2) || (headers - params + 1 > 128))
        {
           sprintf((char *)sipAsciTempBuf, "uri params length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
           return -1;
        }

        sip_clrncpy(temp, params, headers - params);
        sip_uri_parse_params(sipUri, temp);
    }
    
    port = params - 1;
    while (port > host && *port != ']' && *port != ':')
        port--;
    if (*port == ':')
    {
        if (host == port)
            port = params;
        else
        {
            if ((params - port < 2) || (params - port > 8))
            {
                  sprintf((char *)sipAsciTempBuf, "port length out of range\r\n");
                  sip_log_err(sipAsciTempBuf);
                    return -1;          // error cases
            }
            sip_clrncpy(temp, port + 1, params - port - 1);
            sipUri->port = strtoul(temp, NULL, 10);
        }
    }
    else
        port = params;
    
    // adjust port for ipv6 address
    tmp = port;
    while (tmp > host && *tmp != ']')
        tmp--;
    if (*tmp == ']')
    {
        port = tmp;
        while (host < port && *host != '[')
            host++;
        if (host >= port)
            return -1;
    }

    if ((port - host < 2) || (port - host > 128))//port - host > 256
    {
           sprintf((char *)sipAsciTempBuf, "uri domain length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
            return -1;
    }
    
    sip_clrncpy(sipUri->host.addr.domain, host + 1, port - host - 1);

    return 0;
}

int sip_from_parse(SIP_HDR_FROM *from, char *hvalue)
{
    char *dispName;
    char *url;
    char *urlEnd;
    char *genParams;
    char *first;
    char *second;
    char *host;
    char tmp[256];
    WORD    len;

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

    /* How to parse:
         we'll place the pointers:
         dispName  =>  beginning of displayname
         url          =>  beginning of url
         url_end      =>  end       of url
         gen_params   =>  beginning of params
    
         examples:
    
         jack <sip:jack@atosc.org>;tag=34erZ
         ^     ^                ^ ^
    
         sip:jack@atosc.org;tag=34erZ
         ^                ^^      
    */

    dispName = strchr(hvalue, '"');

    url = strchr (hvalue, '<');
    if (url != NULL)
       {
            urlEnd = strchr (url, '>');
            if (urlEnd == NULL)
               return -1;
       }

    /* SIPit day2: this case was not supported
        first '"' is placed after '<' and after '>'
        <sip:ixion@62.254.248.117;method=INVITE>;description="OPEN";expires=28800
        if the fisrt quote is after '<' then
        this is not a quote for a dispName.
    */
   
    if (dispName != NULL)
       {
            if (dispName > url)
               dispName = NULL;
       }

    if ((dispName == NULL) && (url != NULL))
       {// dispName IS A '*token' (not a quoted-string)
            if (hvalue != url)          // dispName exists
           {
               len = url - hvalue;

         if ((len + 1 < 2) || len > 64)
         {
                   sprintf((char *)sipAsciTempBuf, "uri dispName length out of range\r\n");
                   sip_log_err(sipAsciTempBuf);
                     return -1;
         }

             sip_clrncpy(from->dispName, hvalue, len);
           }

            url++;                      // place pointer on the beginning of url
    }
    else
       {
            if ((dispName != NULL) && (url != NULL))
           {    // dispName IS A quoted-string (not a '*token')
            // search for quotes
               first = sip_quote_find (hvalue);
             second = sip_quote_find (first + 1);

             if (second == NULL)
                     return -1;          // if there is only 1 quote: failure

             if ((first > url))
                 return -1;
            
         len = second - first + 1;

             if ((len + 1) >= 2)
                 {
                   if (len > 64)
                   {
                       sprintf((char *)sipAsciTempBuf, "dispName length out of range\r\n");
                       sip_log_err(sipAsciTempBuf);
                       return -1;
                   }

                   sip_clrncpy(from->dispName, first, len);
               }
               // else dispName is empty?
             url = strchr (second + 1, '<');

             if (url == NULL)
                    return -1;          // '<' MUST exist

               url++;
            }
            else
            url = hvalue;           // field does not contains '<' and '>'
       }

    // DISPLAY-NAME SET
    // START of URL KNOWN

    urlEnd = strchr(url, '>');

    if (urlEnd == NULL)             // sip:jack@atosc.org;tag=023
       {                            // We are sure ';' is the delimiter for from-parameters
            host = strchr(url, '@');

            if (host != NULL)
            genParams = strchr(host, ';');
            else
            genParams = strchr(url, ';');

            if (genParams != NULL)
            urlEnd = genParams - 1;
            else
            urlEnd = url + strlen(url);
    }
    else                            // jack <sip:jack@atosc.org;user=phone>;tag=azer
       {
           genParams = strchr(urlEnd, ';');
            urlEnd--;                   // place pointer on the beginning of url
       }
    
    if (genParams != NULL)          // now we are sure a param exist
    {
            if (sip_generic_param_parseall(&from->params, genParams) == -1)
               return -1;
       }
    
    // set the url
    len = urlEnd - url + 1;

       if ((len + 1 < 7) || len > 256)
       {
           sprintf((char *)sipAsciTempBuf, "uri length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
            return -1;
       }

       sip_clrncpy(tmp, url, len);
    
       if (sip_uri_parse(&from->url, tmp) < 0)
           return -1;
 
    return 0;
}

int sip_contact_parse(SIP_HDR_CONTACT *contact, char *hvalue)
{
    return sip_from_parse((SIP_HDR_FROM *)contact, hvalue);
}

int sip_via_parse(SIP_HDR_VIA *via, char *hvalue)
{
    char *version;
    char *protocol;
    char *host;
    char *port;
    char *viaParams;
    char tmp[128];
    char *comment;
    char *ipv6host;

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

    version = strchr(hvalue, '/');
    if (version == NULL)
        return -1;

    protocol = strchr(version + 1, '/');
    if (protocol == NULL)
        return -1;

    // set the version
    if ((protocol - version < 2) || (protocol - version > 128))
    {
           sprintf((char *)sipAsciTempBuf, "via version length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
            return -1;
    }

    sip_clrncpy(tmp, version - 3, protocol - version + 3);
    
    if (sip_ver_api_conv(tmp, &via->version, SIP_STR_TO_API) < 0)
            return -1;
    
    // Here: we avoid matching an additionnal space
    host = strchr(protocol + 1, ' ');
    
    if (host == NULL)
            return -1;
    if (host == protocol + 1)
       {    // there are extra SPACE characters
            while (0 == strncmp(host, " ", 1))
           {
               host++;

             if (strlen(host) == 1)
                     return -1;          // via is malformed
           }
            // here, we match the real space located after the protocol name
            host = strchr(host + 1, ' ');

            if (host == NULL)
            return -1;
       }

    // set the protocol
    if ((host - protocol < 2) || (host - protocol > 128))
    {
           sprintf((char *)sipAsciTempBuf, "via protocol length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
            return -1;
    }

    sip_clrncpy(tmp, protocol + 1, host - protocol - 1);

    if (sip_proto_api_conv(tmp, &via->protocol, SIP_STR_TO_API) < 0)
            return -1;
    
    // comments in Via are not allowed any more in the latest draft (09)
    comment = strchr(host, '(');

    if (comment != NULL)
       {
        /*
        char *end_comment;

        end_comment = strchr (host, ')');
        if (end_comment == NULL)
            return -1;              // if '(' exist ')' MUST exist
        if (end_comment - comment < 2)
            return -1;
        via->comment = (char *) osip_malloc (end_comment - comment);
        if (via->comment == NULL)
            return -1;
        sip_strncpy (via->comment, comment + 1, end_comment - comment - 1);
        comment--;
        */
            return -1;
    }
    else
        comment = host + strlen(host);
    
    viaParams = strchr(host, ';');

    if ((viaParams != NULL) && (viaParams < comment))
    {
        if (comment - viaParams + 1 < 2)
            return -1;
        sip_strncpy(tmp, viaParams, comment - viaParams);
        sip_generic_param_parseall(&via->params, tmp);
    }

    if (viaParams == NULL)
        viaParams = comment;

    // add ipv6 support (0.8.4)
    // Via: SIP/2.0/UDP [mlke::zeezf:ezfz:zef:zefzf]:port;....
    ipv6host = strchr(host, '[');
    if (ipv6host != NULL && ipv6host < viaParams)
    {
        /*
        port = strchr (ipv6host, ']');
        if (port == NULL || port > via_params)
            return -1;

        if (port - ipv6host < 2)
            return -1;
        via->host = (char *) osip_malloc (port - ipv6host);
        if (via->host == NULL)
            return -1;
        sip_clrncpy (via->host, ipv6host + 1, port - ipv6host - 1);

        port = strchr (port, ':');
        */
        return -1;
    }
    else
    {
        port = strchr(host, ':');
        ipv6host = NULL;
    }

    if ((port != NULL) && (port < viaParams))
       {
            if ((viaParams - port < 2) || (viaParams - port > 128))
            {
               sprintf((char *)sipAsciTempBuf, "via port length out of range\r\n");
               sip_log_err(sipAsciTempBuf);
               return -1;
            }

            sip_clrncpy(tmp, port + 1, viaParams - port - 1);
            via->url.port = atol(tmp);
    }
    else
            port = viaParams;

    // host is already set in the case of ipv6
    if (ipv6host != NULL)
        return 0;

    if ((port - host < 2) || (port - host > 64))
    {
           sprintf((char *)sipAsciTempBuf, "via domain length out of range\r\n");
           sip_log_err(sipAsciTempBuf);
            return -1;
    }

    sip_clrncpy(via->url.domain, host + 1, port - host - 1);

    return 0;
}

int sip_to_parse(SIP_HDR_TO *to, char *hvalue)
{
    return sip_from_parse((SIP_HDR_FROM *)to, hvalue);
}

int sip_proxy_require_parse(SIP_HDR_PROXY_REQUIRE *proxyRequire, char *hvalue) 
{
    int     len;
    char     tmp[64];

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

    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    len = strlen(hvalue);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "proxy require value is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, len);

    if (sip_option_tag_api_conv(tmp, &proxyRequire->optionTag, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_record_route_parse(SIP_HDR_RECORD_ROUTE *recRoute, char *hvalue)
{
    return sip_from_parse((SIP_HDR_FROM *)recRoute, hvalue);
}

int sip_require_parse(SIP_HDR_REQUIRE *require, char *hvalue)
{
    int     len;
    char    tmp[64];

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

    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    len = strlen(hvalue);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "require value is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, len);

    if (sip_option_tag_api_conv(tmp, &require->optionTag, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_route_parse(SIP_HDR_ROUTE *route, char *hvalue)
{
    return sip_from_parse((SIP_HDR_FROM *)route, hvalue);
}

int sip_call_id_parse(SIP_HDR_CALL_ID *callId, char *hvalue)
{
    char    *host;
    char    *end;
    WORD    len;

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

    strcpy(callId->value, "");
    strcpy(callId->host, "");

    host = strchr(hvalue, '@');  /* SEARCH FOR '@' */
    end = hvalue + strlen (hvalue);

    if (host == NULL)
        host = end;
    else
    {
        len = end - host - 1;

        if ((len + 2 < 2) || (len > 256))
        {
            sprintf((char *)sipAsciTempBuf, "callId host length out of range\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        sip_clrncpy(callId->host, host + 1, len);
    }
    
    len = host - hvalue;

    if ((len + 1 < 2) || (len > 128))
    {
        sprintf((char *)sipAsciTempBuf, "callId value length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(callId->value, hvalue, len);
    
    return 0;                     /* ok */
}

int sip_cseq_parse(SIP_HDR_CSEQ *cseq, char *hvalue)
{
    char    *method = NULL;
    char    *end = NULL;
    BYTE    tmp[128], len;

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

    cseq->value = 0;
    cseq->method = 0;

    method = strchr(hvalue, ' ');        /* SEARCH FOR SPACE */
    end = hvalue + strlen (hvalue);

    if (method == NULL)
        return -1;
    
    len = method - hvalue;
    if ((len + 1 < 2) || (len > 128))
    {
        sprintf((char *)sipAsciTempBuf, "cseq value length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy((char *)tmp, hvalue, len);
    cseq->value = atol((char *)tmp);
    
    len = end - method;

    if ((len + 1 < 2) || (len > 128))
    {
        sprintf((char *)sipAsciTempBuf, "cseq method length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy((char *)tmp, method + 1, len);

    if (sip_method_api_conv((char *)tmp, &cseq->method, SIP_STR_TO_API) < 0)
        return -1;
    
    return 0;                     /* ok */
}

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

    expires->value = atol(hvalue);
    
    return 0;
}

int sip_mime_version_parse(SIP_HDR_MIME_VERSION *mimiVer, char *hvalue)
{
    int     len;
    BYTE    *mimeVersion;
    char    tmp[64];
 
    if ((mimiVer == NULL) || (hvalue == NULL || hvalue[0] == '\0'))
    {
        sprintf((char *)sipAsciTempBuf, "sip_mime_version_parse: mimiVer or value is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    len = strlen(hvalue);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "mime version value length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    mimeVersion = &mimiVer ->mimeVersion;

    sip_clrncpy(tmp, hvalue, len);

    if (sip_mime_version_api_conv(tmp, mimeVersion, SIP_STR_TO_API) < 0)
        return -1; 
    
    return 0;
}

int sip_time_stamp_parse(SIP_HDR_TIMESTAMP *hdrTimeStamp, char *hvalue)
{
    if (hdrTimeStamp == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_time_stamp_parse: hdrTimeStamp is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (hvalue == NULL || hvalue[0] == '\0')
            return 0;

    hdrTimeStamp->timeStamp = atoll(hvalue);
    
    return 0;
}

int sip_max_forwards_parse(SIP_HDR_MAX_FORWARDS *maxForwards, char *hvalue)
{
    if ((maxForwards == NULL) || (hvalue == NULL) || (hvalue[0] == '\0'))
    {
        sprintf((char *)sipAsciTempBuf, "sip_max_forwards_parse: maxForwards or hvalue is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    maxForwards->value = atol(hvalue);
    
    return 0;
}

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

    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    strcpy ((char *)userAgent->agent, hvalue);

    return 0;
}

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

    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    strcpy ((char *)server->server, hvalue);

    return 0;
}

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

    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    strcpy ((char *)subject->subject, hvalue);

    return 0;
}

int sip_supported_parse(SIP_HDR_SUPPORTED *supported, char *hvalue)
{
    int     len;
    char    tmp[64];

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

    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    len = strlen(hvalue);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "supported value length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, len);

    if (sip_option_tag_api_conv(tmp, &supported->optionTag, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_unsupported_parse(SIP_HDR_UNSUPPORTED *unsupported, char *hvalue)
{
    int     len;
    char    tmp[64];

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

    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    len = strlen(hvalue);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "unsupported value length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, len);

    if (sip_option_tag_api_conv(tmp, &unsupported->optionTag, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_content_type_parse(SIP_CONTENT_TYPE *contentType, char *hvalue)
{
    char    *subType;
    char    *sipContentTypeParams;
    char    tmp[64];

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

    /* How to parse:

     we'll place the pointers:
     subType                =>  beginning of subtype
     sipContentTypeParams   =>  beginning of params

     examples:

     application/multipart ; boundary=
     ^          ^
    */
    
    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    subType = strchr(hvalue, '/');
    sipContentTypeParams = strchr(hvalue, ';');

    if (subType == NULL)
        return -1;

    if (sipContentTypeParams != NULL)
    {
        if (sip_generic_param_parseall(&contentType->params, sipContentTypeParams) == -1)
            return -1;
    }
    else
        sipContentTypeParams = subType + strlen(subType);

    if ((subType - hvalue + 1 < 2) || (subType - hvalue > 64))
    {
        sprintf((char *)sipAsciTempBuf, "content type value length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip_clrncpy(tmp, hvalue, subType - hvalue);

    if (sip_content_type_api_conv(tmp, &contentType->type, SIP_STR_TO_API) < 0)
        return -1;
    
    if ((sipContentTypeParams - subType < 2)    || (sipContentTypeParams - subType > 64))
    {
        sprintf((char *)sipAsciTempBuf, "content type params length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip_clrncpy(tmp, subType + 1, sipContentTypeParams - subType - 1);

    if (sip_content_sub_type_api_conv(tmp, &contentType->subType, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_content_disposition_parse(SIP_CONTENT_DISPOSITION *contentDisposition, char *hvalue)
{
    char    *sipContentDispositionParams;
    char    tmp[64];

    if (contentDisposition == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_content_disposition_parse: contentDisposition is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    if (hvalue == NULL || hvalue[0] == '\0')
        return 0;

    sipContentDispositionParams = strchr(hvalue, ';');

    if (sipContentDispositionParams != NULL)
    {
            if (sip_generic_param_parseall(&contentDisposition->params, sipContentDispositionParams) == -1)
               return -1;
    }
    else
        sipContentDispositionParams = hvalue + strlen(hvalue);

    if ((sipContentDispositionParams - hvalue < 2) || (sipContentDispositionParams - hvalue > 64))
    {
        sprintf((char *)sipAsciTempBuf, "content disposition value length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, sipContentDispositionParams - hvalue);
    
    if (sip_content_disposition_api_conv(tmp, &contentDisposition->contentDisposition, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_content_language_parse(BYTE *contentLanguage, char *hvalue)
{
    int     len;
    char    tmp[64];

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    len = strlen(hvalue);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "content language value length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, len);

    if (sip_content_language_api_conv(tmp, contentLanguage, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_content_encoding_parse(BYTE *contentEncoding, char *hvalue) 
{
    int      len;
    char     tmp[64];

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    len = strlen(hvalue);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "content encoding value length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, len);
    
    if (sip_content_encoding_api_conv(tmp, contentEncoding, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_content_length_parse(SIP_ENTITY *sipEntity, char *hvalue)
{
    if (sipEntity == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_content_length_parse: sipEntity is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    sipEntity->sipHdrContentLength = atol(hvalue);
    
    return 0;
}

int sip_accept_parse(SIP_HDR_ACCEPT *accept, char *hvalue)
{
    char    *subType;
    char    *sipAccepttTypeParams;
    char    tmp[64];

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    subType = strchr(hvalue, '/');
    sipAccepttTypeParams = strchr(hvalue, ';');

    if (subType == NULL)
        return -1;

    if (sipAccepttTypeParams != NULL)
    {
        if (sip_generic_param_parseall(&accept->params, sipAccepttTypeParams) == -1)
            return -1;
    }
    else
        sipAccepttTypeParams = subType + strlen(subType);

    if ((subType - hvalue + 1 < 2) || (subType - hvalue > 64))
    {
        sprintf((char *)sipAsciTempBuf, "accept type length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip_clrncpy(tmp, hvalue, subType - hvalue);
    
    if (sip_accept_type_api_conv(tmp, &accept->type, SIP_STR_TO_API) < 0)
        return -1;
    
    if ((sipAccepttTypeParams - subType < 2)    || (sipAccepttTypeParams - subType > 64))
    {
        sprintf((char *)sipAsciTempBuf, "accept sub type length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip_clrncpy(tmp, subType + 1, sipAccepttTypeParams - subType - 1);
    
    if (sip_accept_sub_type_api_conv(tmp, &accept->subType, SIP_STR_TO_API) < 0)
        return -1;
    
    return 0;
}

int sip_accept_encoding_parse(SIP_HDR_ACCEPT_ENCODING *encoding, char *hvalue)
{
    char    *sipAcceptEncodingParams;
    char    tmp[64];

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    sipAcceptEncodingParams = strchr(hvalue, ';');

    if (sipAcceptEncodingParams != NULL)
    {
        if (sip_generic_param_parseall(&encoding->params, sipAcceptEncodingParams) == -1)
            return -1;
    }
    else
        sipAcceptEncodingParams = hvalue + strlen(hvalue);

    if ((sipAcceptEncodingParams - hvalue < 2) || (sipAcceptEncodingParams - hvalue > 64))
    {
        sprintf((char *)sipAsciTempBuf, "accept encoding length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, sipAcceptEncodingParams - hvalue);
    
    if (sip_accept_encoding_api_conv(tmp, &encoding->acceptEncoding, SIP_STR_TO_API) < 0)
        return -1;

    return 0;   
}

int sip_accept_language_parse(SIP_HDR_ACCEPT_LANGUAGE *language, char *hvalue)
{
    char    *sipAcceptLanguageParams;
    char    tmp[64];

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    sipAcceptLanguageParams = strchr(hvalue, ';');

    if (sipAcceptLanguageParams != NULL)
    {
        if (sip_generic_param_parseall(&language->params, sipAcceptLanguageParams) == -1)
            return -1;
    }
    else
        sipAcceptLanguageParams = hvalue + strlen(hvalue);

    if ((sipAcceptLanguageParams - hvalue < 2) || (sipAcceptLanguageParams - hvalue > 64))
    {
        sprintf((char *)sipAsciTempBuf, "accept language value length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, sipAcceptLanguageParams - hvalue);
    
    if (sip_accept_language_api_conv(tmp, &language->acceptLanguage, SIP_STR_TO_API) < 0)
        return -1;

    return 0;
}

int sip_allow_parse(SIP_HDR_ALLOW *allow, char *hvalue)
{
    char    *comma;
    char    *buf = hvalue;
    char     tmp[64];
    int        ret;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    allow->num = 0;

    for (;;)
    {
        comma = strchr(buf, ',');

        if (comma == NULL)
        {
            comma = buf + strlen(buf);
            break;
        }

        if ((comma - buf < 2) || (comma - buf > 64))
        {
            sprintf((char *)sipAsciTempBuf, "allow method length out of range\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        sip_clrncpy(tmp, buf, comma - buf);

        if ((ret = sip_allow_api_conv(tmp, &allow->allowMethod[allow->num], SIP_STR_TO_API)) == -1)
            return -1;

        if (ret == 0)
            allow->num = allow->num + 1;

        buf = comma + 1;
    }

    if ((comma - buf < 2) || (comma - buf > 64))
    {
        sprintf((char *)sipAsciTempBuf, "allow last method length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, buf, comma - buf);

    if ((ret = sip_allow_api_conv(tmp, &allow->allowMethod[allow->num], SIP_STR_TO_API)) == -1)
        return -1;

    if (ret == 0)
        allow->num = allow->num + 1;
    
    return 0;
}

int sip_date_time_parse(SIP_HDR_DATE *date, char *time)
{
    int     i;
    int     len;
    char    *buf;
    char    *colon;
    char    tmp[64];

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

    if ((time == NULL) || (time[0] == '\0'))
        return 0;

    buf = time;

    for (i = 0; i < 2; i++)
    {
        if (((colon = strchr(buf, ':')) == NULL) || (colon < buf))
        {
            sprintf((char *)sipAsciTempBuf, "Malformed date time\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        if (colon - buf > 64)
        {
            sprintf((char *)sipAsciTempBuf, "date time length is too long\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        sip_clrncpy(tmp, buf, colon - buf);

        switch (i)
        {
        case 0:
            date->hour = atoi(tmp);
            break;
        case 1:
            date->min = atoi(tmp);
            break;
        default:
            return -1;
        }

        buf = colon + 1;
    }

    len = strlen(buf);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "date time second length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, buf, len);

    date->sec = atoi(tmp);

    return 0;
}

int sip_date_parse(SIP_HDR_DATE *date, char *hvalue)
{
    int     i;
    int     len;
    char    *comma;
    char    *sp;
    char    *nextSp;
    char    tmp[64];

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    if (((comma = strchr(hvalue, ',')) == NULL) || (comma <= hvalue))
        return -1;

    if (comma - hvalue > 64)
    {
        sprintf((char *)sipAsciTempBuf, "date weekday length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, hvalue, comma - hvalue);

    sip_date_weekday_api_conv(tmp, &date->wkDay, SIP_STR_TO_API);

    if (comma[1] == ' ')
        sp = comma + 2;
    else
        sp = comma + 1;

    for (i = 0; i < 4; i++)
    {
        if (((nextSp = strchr(sp, ' ')) == NULL) || (nextSp < sp))
        {
            sprintf((char *)sipAsciTempBuf, "Malformed sip date\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        if (nextSp - sp > 64)
        {
            sprintf((char *)sipAsciTempBuf, "date length is too long\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        sip_clrncpy(tmp, sp, nextSp - sp);

        switch (i)
        {
        case 0:
            date->mDay = atoi(tmp);
            break;
        case 1:
            if (sip_date_month_api_conv(tmp, &date->mon, SIP_STR_TO_API) < 0)
            {
                return -1;
            } 
            break;
        case 2:
            date->year = atol(tmp);
            break;
        case 3:
            sip_date_time_parse(date, tmp);
            break;
        default:
           return -1;
        }

        sp = nextSp + 1;
    }

    len = strlen(sp);

    if (len > 64)
    {
        sprintf((char *)sipAsciTempBuf, "date type length is too long\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, sp, len);

    if (sip_date_type_api_conv(tmp, &date->dateType, SIP_STR_TO_API) < 0)
    {
        return -1;
    }

    return 0;
}

int sip_refer_to_parse(SIP_HDR_REFER_TO *referTo, char *hvalue)
{
    return sip_from_parse((SIP_HDR_FROM *)referTo, hvalue);
}

int sip_envet_parse(SIP_HDR_EVENT *event, char *hvalue)
{
    if ((event == NULL) || (hvalue == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_envet_parse: event or hvalue is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    strcpy(event->event, hvalue);

    return 0;
}

int sip_subscription_state_parse(SIP_HDR_SUBSCRIPTION_STATE *subscriptionState, char *hvalue)
{
    if ((subscriptionState == NULL) || (hvalue == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_subscription_state_parse: subscriptionState or hvalue is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    strcpy(subscriptionState->subscriptionState, hvalue);

    return 0;
}

int sip_message_set_accept(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_ACCEPT       *accept;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
    {
//        sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_ACCEPT_EMPTY_MASK;
        return 0;
    }

    accept = &sip->sipApiMsg.sipMsg.sipHdrAccept;

    if (sip_accept_parse(accept, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip accept parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_ACCEPT_MASK;
    
    return 0;
}

int sip_message_set_accept_encoding(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_ACCEPT_ENCODING  *encoding;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    encoding = &sip->sipApiMsg.sipMsg.sipHdrAcceptEncoding;

    if (sip_accept_encoding_parse(encoding, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip accept encoding parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_ACCEPT_ENCODING_MASK;
    
    return 0;
}

int sip_message_set_accept_language(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_ACCEPT_LANGUAGE  *language;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    language = &sip->sipApiMsg.sipMsg.sipHdrAcceptLanguage;

    if (sip_accept_language_parse(language, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip accept language failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_ACCEPT_LANGUAGE_MASK;
    
    return 0;
}

int sip_message_set_alert_info(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_allow(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_ALLOW       *allow;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    allow = &sip->sipApiMsg.sipMsg.sipHdrAllow;

    if (sip_allow_parse(allow, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip allow parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_ALLOW_MASK;
    
    return 0;
}

int sip_message_set_authentication_info(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_authorization(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_content_type(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_CONTENT_TYPE    *contentType;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    contentType = &sip->sipApiMsg.sipMsg.sipEntity.sipHdrContentType;
    
    if (sip_content_type_parse(contentType, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip content type parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipEntity.sipEntityHdrFlag[0] |= SIP_HDR_CONTENT_TYPE_MASK;
    
    return 0;
}

int sip_message_set_content_disposition(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_CONTENT_DISPOSITION *contentDisposition;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    contentDisposition= &sip->sipApiMsg.sipMsg.sipEntity.sipHdrContentDisposition;
    
    if (sip_content_disposition_parse(contentDisposition, hvalue) < 0)
    {
        sprintf((char *)sipEncBuf, "sip content disposition parse failed\r\n");
        sip_log_err(sipEncBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipEntity.sipEntityHdrFlag[0] |= SIP_HDR_CONTENT_DISPOSITION_MASK;
    
    return 0;   
}

int sip_message_set_content_encoding(SIP_API_STRUCT *sip, char *hvalue)
{
    BYTE    *contentEncoding;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    contentEncoding = &sip->sipApiMsg.sipMsg.sipEntity.sipHdrContentEncoding;

    if (sip_content_encoding_parse(contentEncoding, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip content encoding parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipEntity.sipEntityHdrFlag[0] |= SIP_HDR_CONTENT_ENCODING_MASK;
    
    return 0;
}

int sip_message_set_content_language(SIP_API_STRUCT *sip, char *hvalue)
{
    BYTE *contentLanguage;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    contentLanguage = &sip->sipApiMsg.sipMsg.sipEntity.sipHdrContentLanguage;

    if (sip_content_language_parse(contentLanguage, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip content language parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipEntity.sipEntityHdrFlag[0] |= SIP_HDR_CONTENT_LANGUAGE_MASK;
    
    return 0;
}

int sip_message_set_content_length(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_ENTITY  *sipEntity;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_content_length: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    sipEntity = &sip->sipApiMsg.sipMsg.sipEntity;
    
    if (sip_content_length_parse(sipEntity, hvalue) < 0)
        return -1;

    sip->sipApiMsg.sipMsg.sipEntity.sipEntityHdrFlag[0] |= SIP_HDR_CONTENT_LENGTH_MASK;
    
    return 0;
}

int sip_message_set_call_id(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_CALL_ID     *hdrCallId;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_call_id: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    hdrCallId = &sip->sipApiMsg.sipMsg.sipHdrCallId;

    if (sip_call_id_parse(hdrCallId, hvalue) < 0)
    {
        strcpy(hdrCallId->value, "");
        return -1;
    }
    
    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_CALL_ID_MASK;
    
    return 0;
}

int sip_message_set_cseq(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_CSEQ    *hdrCseq;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_cseq: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    hdrCseq = &sip->sipApiMsg.sipMsg.sipHdrCseq;

    if (sip_cseq_parse(hdrCseq, hvalue) < 0)
    {
        hdrCseq->value = 0;
        hdrCseq->method = 0;
        sprintf((char *)sipAsciTempBuf, "sip cseq parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_CSEQ_MASK;
    
    return 0;
}

int sip_message_set_date(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_DATE    *date;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    date = &sip->sipApiMsg.sipMsg.sipHdrDate;

    if (sip_date_parse(date, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip date parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_DATE_MASK;

    return 0;
}

int sip_message_set_expires(SIP_API_STRUCT *sip, char *hvalue)
{   
    SIP_HDR_EXPIRES      *expires;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_expires: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    expires = &sip->sipApiMsg.sipMsg.sipHdrExpires;
    
    if (sip_expires_parse(expires, hvalue) < 0)
        return -1;

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_EXPIRES_MASK;

    return 0;
}

int sip_message_set_call_info(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_error_info(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_event(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_EVENT    *event;

    if ((sip == NULL) || (hvalue == NULL) || (hvalue[0] == '\0'))
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_event: sip or hvalue is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    event = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrEvent;
    
    if (sip_envet_parse(event, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip event parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_EVENT_MASK;

    return 0;
}

int sip_message_set_from(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_FROM    *hdrFrom;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_from: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    hdrFrom = &sip->sipApiMsg.sipMsg.sipHdrFrom;
    
    if (sip_from_parse(hdrFrom, hvalue) < 0)
        return -1;
    
    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_FROM_MASK;
    
    return 0;
}

int sip_message_set_contact(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_CONTACTS    *contacts;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_contact: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    contacts = &sip->sipApiMsg.sipMsg.sipHdrContacts;
    
    if (contacts->num >= SIP_MAX_NUM_OF_CONTACTS)
        return -1;
    
    if (sip_contact_parse(&contacts->contacts[contacts->num], hvalue) < 0)
        return -1;
    
    contacts->head = 0;
    contacts->num++;
    
    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_CONTACT_MASK;
    
    return 0;
}

int sip_message_set_mime_version(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_MIME_VERSION  *mimeVer;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_mime_version: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    mimeVer = &sip->sipApiMsg.sipMsg.sipHdrMimeVer;

    if (sip_mime_version_parse(mimeVer, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip mime version parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_MIME_VERSION_MASK;
    
    return 0;
}

int sip_message_set_proxy_authenticate(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_proxy_authentication_info(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_proxy_authorization(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_proxy_require(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_PROXY_REQUIRE       *proxyRequire;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    proxyRequire = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrProxyRequire;

    if (sip_proxy_require_parse(proxyRequire, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip proxy require parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |=SIP_HDR_PROXY_REQUIRE_MASK;

    return 0;
}

int sip_message_set_record_route(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_RECORD_ROUTES   *recRoutes;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_record_route: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    recRoutes = &sip->sipApiMsg.sipMsg.sipHdrRecordRoutes;
    
    if (recRoutes->num >= SIP_MAX_NUM_OF_RECORD_ROUTES)
        return -1;
    
    if (sip_record_route_parse(&recRoutes->recRoutes[recRoutes->num + 1], hvalue) < 0)
        return -1;
    
    if (recRoutes->num == 0)
        recRoutes->head = 1;
    
    recRoutes->num++;
    
    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_RECORD_ROUTE_MASK;
    
    return 0;
}

int sip_message_set_refer_to(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_REFER_TO    *referTo;

    if ((sip == NULL) || (hvalue == NULL) || (hvalue[0] == '\0'))
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_refer_to: sip or hvalue is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    referTo = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrReferTo;

    if (sip_refer_to_parse(referTo, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip refer-to parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_REFER_TO_MASK;

    return 0;
}

int sip_message_set_require(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_REQUIRE     *require;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    require = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrRequire;

    if (sip_require_parse(require, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip require parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_REQUIRE_MASK;

    return 0;
}

int sip_message_set_route(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_ROUTES  *routes;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_route: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    routes = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrRoutes;
    
    if (routes->num >= SIP_MAX_NUM_OF_RECORD_ROUTES)
        return -1;
    
    if (sip_route_parse(&routes->routes[routes->num + 1], hvalue) < 0)
        return -1;
    
    if (routes->num == 0)
        routes->head = 1;
    
    routes->num++;
    
    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_ROUTE_MASK;
    
    return 0;
}

int sip_message_set_server(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_SERVER      *server;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    server = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipRspHdr.sipHdrServer;
    
    if (sip_server_parse(server, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip server parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_SERVER_MASK;

    return 0;
}

int sip_message_set_subject(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_SUBJECT     *subject;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    subject = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrSubject;
    
    if (sip_subject_parse(subject, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip subject parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_SUBJECT_MASK;

    return 0;
}

int sip_message_set_subscription_state(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_SUBSCRIPTION_STATE    *subscriptionState;

    if ((sip == NULL) || (hvalue == NULL) || (hvalue[0] == '\0'))
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_subscription_state: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    subscriptionState = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrSubscriptionState;

    if (sip_subscription_state_parse(subscriptionState, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip subscription state parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_SUBSCRIPTION_STATE_MASK;

    return 0;
}

int sip_message_set_supported(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_SUPPORTED       *supported;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    supported = &sip->sipApiMsg.sipMsg.sipHdrSupported;

    if (sip_supported_parse(supported, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip supported parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_SUPPORTED_MASK;

    return 0;
}

int sip_message_set_to(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_TO  *hdrTo;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_to: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    hdrTo = &sip->sipApiMsg.sipMsg.sipHdrTo;
    
    if (sip_to_parse(hdrTo, hvalue) < 0)
        return -1;

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_TO_MASK;
    
    return 0;
}

int sip_message_set_time_stamp(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_TIMESTAMP    *hdrTimeStamp;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    hdrTimeStamp = &sip->sipApiMsg.sipMsg.sipHdrStamp;

    if (sip_time_stamp_parse(hdrTimeStamp, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip time stamp parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_TIMESTAMP_MASK;

    return 0;
}

int sip_message_set_unsupported(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_UNSUPPORTED     *unsupported;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    unsupported = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipRspHdr.sipHdrUnsupported;

    if (sip_unsupported_parse(unsupported, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip unsupported parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_UNSUPPORTED_MASK;

    return 0;    
}

int sip_message_set_user_agent(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_USER_AGENT      *userAgent;

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

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;

    userAgent = &sip->sipApiMsg.sipMsg.sipHdrUserAgent;

    if (sip_user_agent_parse(userAgent, hvalue) < 0)
    {
        sprintf((char *)sipAsciTempBuf, "sip user agent parse failed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_USER_AGENT_MASK;

    return 0;   
}

int sip_message_set_via(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_VIAS    *vias;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_via: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    vias = &sip->sipApiMsg.sipMsg.sipHdrVias;
    
    if (vias->num >= SIP_MAX_NUM_OF_VIAS)
        return -1;
    
    if (sip_via_parse(&vias->vias[vias->num + 1], hvalue) < 0)
        return -1;
    
    if (vias->num == 0)
        vias->head = 1;
    
    vias->num++;
    
    sip->sipApiMsg.sipMsg.sipGenHdrFlag[0] |= SIP_HDR_VIA_MASK;
    
    return 0;
}

int sip_message_set_www_authenticate(SIP_API_STRUCT *sip, char *hvalue)
{
    return 0;
}

int sip_message_set_max_forwards(SIP_API_STRUCT *sip, char *hvalue)
{
    SIP_HDR_MAX_FORWARDS    *hdrMaxForwards;
    
    if (sip == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_message_set_max_forwards: sip is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((hvalue == NULL) || (hvalue[0] == '\0'))
        return 0;
    
    hdrMaxForwards = &sip->sipApiMsg.sipMsg.sipReStruct.sipReHdr.sipReqHdr.sipHdrMaxForwards;
    
    if (sip_max_forwards_parse(hdrMaxForwards, hvalue) < 0)
        return -1;

    sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] |= SIP_HDR_MAX_FORWARDS_MASK;
    
    return 0;
}

void sip_tolower(char *str)
{
    int i;
    int len;

    if (str == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_tolower: str is NULL\n");
        sip_log_err(sipAsciTempBuf);
        return;
    }

    len = strlen(str);

    for (i = 0; i <= len - 1; i++)
    {
        if ('A' <= str[i] && str[i] <= 'Z')
            str[i] = str[i] + 32;
    }
}

int sip_find_next_crlf(char *startOfHeader, char **endOfHeader)
{
    char *soh = startOfHeader;

    *endOfHeader = NULL;

    while (('\r' != *soh) && ('\n' != *soh))
    {
        if (*soh)
            soh++;
        else
        {
            sprintf((char *)sipAsciTempBuf, "Final CRLF is missing\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }
    
    // case 1: CRLF is the separator
    // case 2 or 3: CR or LF is the separator
    if (('\r' == soh[0]) && ('\n' == soh[1]))
        soh = soh + 1;

    // VERIFY if TMP is the end of header or LWS.
    // LWS are extra SP, HT, CR and LF contained in headers.
    if ((' ' == soh[1]) || ('\t' == soh[1]))
    {
        // incoming message that potentially
        // contains LWS must be processed with
        // sip_util_replace_all_lws(char *)
        sprintf((char *)sipAsciTempBuf, "Message that contains LWS must be processed with sip_util_replace_all_lws(char *tmp) before being parsed\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    *endOfHeader = soh + 1;
    
    return 0;
}

// For better performance
// Calculates a hash value for the given string
DWORD sip_hash(char *str)
{
    DWORD hash = 5373;//5381
    int c;

    if (str == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "sip_hash: str is NULL\n");
        sip_log_err(sipAsciTempBuf);
    }

    while ((c = *str++) != '\0')
        hash = (hash << 4) + hash + c;//5

    return hash;
}

// This method must be called before using the parser
int sip_parser_init(void)
{
    int     i = 0;
    int     count = 0;
    DWORD   hash;
    
    sipParseConfig[i].hname = SIP_HNAME_ACCEPT;
    sipParseConfig[i++].setheader = (&sip_message_set_accept);
    sipParseConfig[i].hname = SIP_HNAME_ACCEPT_ENCODING;
    sipParseConfig[i++].setheader = (&sip_message_set_accept_encoding);
    sipParseConfig[i].hname = SIP_HNAME_ACCEPT_LANGUAGE;
    sipParseConfig[i++].setheader = (&sip_message_set_accept_language);
    sipParseConfig[i].hname = SIP_HNAME_ALERT_INFO;
    sipParseConfig[i++].setheader = (&sip_message_set_alert_info);
    sipParseConfig[i].hname = SIP_HNAME_ALLOW;
    sipParseConfig[i++].setheader = (&sip_message_set_allow);
/*    sipParseConfig[i].hname = SIP_HNAME_AUTHENTICATION_INFO;
    sipParseConfig[i++].setheader = (&sip_message_set_authentication_info);
    sipParseConfig[i].hname = SIP_HNAME_AUTHORIZATION;
    sipParseConfig[i++].setheader = (&sip_message_set_authorization);*/
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_TYPE_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_content_type);
    sipParseConfig[i].hname = SIP_HNAME_CALL_ID;
    sipParseConfig[i++].setheader = (&sip_message_set_call_id);
    sipParseConfig[i].hname = SIP_HNAME_CALL_INFO;
    sipParseConfig[i++].setheader = (&sip_message_set_call_info);
    sipParseConfig[i].hname = SIP_HNAME_CONTACT;
    sipParseConfig[i++].setheader = (&sip_message_set_contact);
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_ENCODING;
    sipParseConfig[i++].setheader = (&sip_message_set_content_encoding);
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_LENGTH;
    sipParseConfig[i++].setheader = (&sip_message_set_content_length);
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_TYPE;
    sipParseConfig[i++].setheader = (&sip_message_set_content_type);
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_DISPOSITION;
    sipParseConfig[i++].setheader =(&sip_message_set_content_disposition);
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_LANGUAGE;
    sipParseConfig[i++].setheader =(&sip_message_set_content_language); 
    sipParseConfig[i].hname = SIP_HNAME_CSEQ;
    sipParseConfig[i++].setheader = (&sip_message_set_cseq);
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_ENCODING_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_content_encoding);
    sipParseConfig[i].hname = SIP_HNAME_SIPDATE;
    sipParseConfig[i++].setheader = (&sip_message_set_date);
    sipParseConfig[i].hname = SIP_HNAME_EXPIRES;
    sipParseConfig[i++].setheader = (&sip_message_set_expires);
    sipParseConfig[i].hname = SIP_HNAME_ERROR_INFO;
    sipParseConfig[i++].setheader = (&sip_message_set_error_info);
    sipParseConfig[i].hname = SIP_HNAME_EVENT;
    sipParseConfig[i++].setheader = (&sip_message_set_event);
    sipParseConfig[i].hname = SIP_HNAME_FROM_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_from);
    sipParseConfig[i].hname = SIP_HNAME_FROM;
    sipParseConfig[i++].setheader = (&sip_message_set_from);
    sipParseConfig[i].hname = SIP_HNAME_CALL_ID_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_call_id);
    sipParseConfig[i].hname = SIP_HNAME_CONTENT_LENGTH_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_content_length);
    sipParseConfig[i].hname = SIP_HNAME_CONTACT_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_contact);
    sipParseConfig[i].hname = SIP_HNAME_MIME_VERSION;
    sipParseConfig[i++].setheader = (&sip_message_set_mime_version);
    sipParseConfig[i].hname = SIP_HNAME_PROXY_AUTHENTICATE;
    sipParseConfig[i++].setheader = (&sip_message_set_proxy_authenticate);
/*    sipParseConfig[i].hname = SIP_HNAME_PROXY_AUTHENTICATION_INFO;
    sipParseConfig[i++].setheader = (&sip_message_set_proxy_authentication_info);
    sipParseConfig[i].hname = SIP_HNAME_PROXY_AUTHORIZATION;
    sipParseConfig[i++].setheader = (&sip_message_set_proxy_authorization);*/
    sipParseConfig[i].hname = SIP_HNAME_PROXY_REQUIRE;
    sipParseConfig[i++].setheader = (&sip_message_set_proxy_require);
    sipParseConfig[i].hname = SIP_HNAME_RECORD_ROUTE;
    sipParseConfig[i++].setheader = (&sip_message_set_record_route);
    sipParseConfig[i].hname = SIP_HNAME_REQUIRE;
    sipParseConfig[i++].setheader = (&sip_message_set_require);
    sipParseConfig[i].hname = SIP_HNAME_ROUTE;
    sipParseConfig[i++].setheader = (&sip_message_set_route);
    sipParseConfig[i].hname = SIP_HNAME_REFER_TO_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_refer_to);
    sipParseConfig[i].hname = SIP_HNAME_REFER_TO;
    sipParseConfig[i++].setheader = (&sip_message_set_refer_to);
    sipParseConfig[i].hname = SIP_HNAME_SERVER;
    sipParseConfig[i++].setheader = (&sip_message_set_server);
    sipParseConfig[i].hname = SIP_HNAME_SUBJECT;
    sipParseConfig[i++].setheader = (&sip_message_set_subject);
    sipParseConfig[i].hname = SIP_HNAME_SUBJECT_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_subject);
    sipParseConfig[i].hname = SIP_HNAME_SUPPORTED_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_supported);
    sipParseConfig[i].hname = SIP_HNAME_SUPPORTED;
    sipParseConfig[i++].setheader = (&sip_message_set_supported);
    sipParseConfig[i].hname = SIP_HNAME_TO_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_to);
    sipParseConfig[i].hname = SIP_HNAME_TO;
    sipParseConfig[i++].setheader = (&sip_message_set_to);
    sipParseConfig[i].hname = SIP_HNAME_TIMESTAMP;
    sipParseConfig[i++].setheader = (&sip_message_set_time_stamp);
    sipParseConfig[i].hname = SIP_HNAME_USER_AGENT;
    sipParseConfig[i++].setheader = (&sip_message_set_user_agent);
    sipParseConfig[i].hname = SIP_HNAME_UNSUPPORTED;
    sipParseConfig[i++].setheader = (&sip_message_set_unsupported);
    sipParseConfig[i].hname = SIP_HNAME_SUBSCRIPTION_STATE;
    sipParseConfig[i++].setheader = (&sip_message_set_subscription_state);
    sipParseConfig[i].hname = SIP_HNAME_VIA_SHORT;
    sipParseConfig[i++].setheader = (&sip_message_set_via);
    sipParseConfig[i].hname = SIP_HNAME_VIA;
    sipParseConfig[i++].setheader = (&sip_message_set_via);
    sipParseConfig[i].hname = SIP_HNAME_WWW_AUTHENTICATE;
    sipParseConfig[i++].setheader = (&sip_message_set_www_authenticate);
    sipParseConfig[i].hname = SIP_HNAME_MAX_FORWARDS;
    sipParseConfig[i++].setheader = (&sip_message_set_max_forwards);
    
    // build up hash table for fast header lookup

    // initialize the table
    for (i = 0; i < SIP_HASH_TABLE_SIZE; i++)
    {
        sipHdrRefTable[i] = -1;    // no entry
    }

    for (i = 0; i < SIP_MAX_NUM_OF_HEADERS; i++)
    {
        // Calculate hash value using lower case
        hash = sip_hash(sipParseConfig[i].hname);
        hash = hash%SIP_HASH_TABLE_SIZE;

        while(sipHdrRefTable[hash] != -1)
        {
            hash = (hash+1)%SIP_HASH_TABLE_SIZE;
            if (++count >= SIP_HASH_TABLE_SIZE)
            {
                printf("Conflict with current hash table size\r\n");
                return -1;
            }
        }

        sipHdrRefTable[hash] = i;

    }

    return 0;
}

// improved look-up mechanism
// precondition: hname is all lowercase
int sip_message_is_known_header (char *hname)
{
    unsigned int hash;
    int index;
    int count = 0;

    hash = sip_hash(hname);
    hash = hash % SIP_HASH_TABLE_SIZE;
    index = sipHdrRefTable[hash];

    while ((index == -1) || (strcmp(sipParseConfig[index].hname, hname) != 0))
    {
        hash = (hash+1) % SIP_HASH_TABLE_SIZE;
        index = sipHdrRefTable[hash];
        if (++count >= SIP_HASH_TABLE_SIZE)
        	return -1;
    }

    return index;
}

// This method calls the method that is able to parse the header
int sip_message_call_method(int i, SIP_API_STRUCT *sip, char *hvalue)
{
    return sipParseConfig[i].setheader(sip, hvalue);
}

int sip_message_set_header(SIP_API_STRUCT *sip, char *hname, char *hvalue)
{
    int index;

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

    if (hname == NULL)
        return -1;

    // some headers are analysed completely
    // this method is used for selective parsing
    index = sip_message_is_known_header(hname);
    if (index >= 0)
       {
           if (sip_message_call_method(index, sip, hvalue) < 0)
           {
               sprintf((char *)sipAsciTempBuf, "Could not set header: \"%s\" %s\r\n", hname, hvalue);
               sip_log_err(sipAsciTempBuf);
               return -1;
           }
           return 0;
       }
    
    // Doesn't support unknown header parsing for the moment

    return 0;
}

int sip_message_set_multiple_header(SIP_API_STRUCT *sip, char *hname, char *hvalue)
{
    char *ptr;                    // current location of the search
    char *comma;                  // This is the separator we are elooking for
    //char *beg;                    // beg of a header
    //char *end;                    // end of a header
    //char *quote1;                 // first quote of a pair of quotes
    //char *quote2;                 // second quuote of a pair of quotes
    size_t hname_len;

    // Find header based upon lowercase comparison
    sip_tolower(hname);

    if (hvalue == NULL)
    {
        if (sip_message_set_header(sip, hname, hvalue) < 0)
            return -1;

        return 0;
    }

    ptr = hvalue;
    comma = strchr(ptr, ',');

    hname_len = strlen(hname);

    if (comma == NULL
        || (hname_len == 4 && strncmp (hname, "date", 4) == 0)
        || (hname_len == 5 && strncmp (hname, "allow", 5) == 0)
        || (hname_len == 2 && strncmp (hname, "to", 2) == 0)
        || (hname_len == 4 && strncmp (hname, "from", 4) == 0)
        || (hname_len == 3 && strncmp (hname, "via", 3) == 0)
        || (hname_len == 7 && strncmp (hname, "call-id", 7) == 0)
        || (hname_len == 4 && strncmp (hname, "cseq", 4) == 0)
        || (hname_len == 7 && strncmp (hname, "subject", 7) == 0)
        || (hname_len == 7 && strncmp (hname, "expires", 7) == 0)
        || (hname_len == 7 && strncmp (hname, "contact", 7) == 0)
        || (hname_len == 6 && strncmp (hname, "server", 6) == 0)
        || (hname_len == 9 && strncmp (hname, "supported", 9) == 0)
        || (hname_len == 6 && strncmp (hname, "accept", 6) == 0)
        || (hname_len == 11 && strncmp (hname, "unsupported", 11) == 0)
        || (hname_len == 15 && strncmp (hname, "accept-language", 15) == 0)
        || (hname_len == 15 && strncmp (hname, "accept-encoding", 15) == 0)
        || (hname_len == 10 && strncmp (hname, "user-agent", 10) == 0)
        || (hname_len == 16 && strncmp (hname, "www-authenticate", 16) == 0)
        || (hname_len == 19 && strncmp (hname, "authentication-info", 19) == 0)
        || (hname_len == 18 && strncmp (hname, "proxy-authenticate", 18) == 0)
        || (hname_len == 19 && strncmp (hname, "proxy-authorization", 19) == 0)
        || (hname_len == 25 && strncmp (hname, "proxy-authentication-info", 25) == 0)
        || (hname_len == 12 && strncmp (hname, "organization", 12) == 0)
        || (hname_len == 13 && strncmp (hname, "authorization", 13) == 0)
        || (hname_len == 12 && strncmp (hname, "max-forwards", 12) == 0)
        || (hname_len == 12 && strncmp (hname, "content-type", 12) == 0)
        || (hname_len == 14 && strncmp (hname, "content-length", 14) == 0))
        // there is no multiple header! likely
        // to happen most of the time...
        // or hname is a TEXT-UTF8-TRIM and may
        // contain a comma. this is not a separator
        // THIS DOES NOT WORK FOR UNKNOWN HEADER!!!!
    {
        if ((sip->sipApiType == SIP_API_REQ_MSG) 
        	&& ((hname_len == 11 && strncmp (hname, "unsupported", 11) == 0) 
        	    || (hname_len == 6 && strncmp (hname, "server", 6) == 0)))
        {
            sprintf((char *)sipAsciTempBuf, "sip request msg have res header\r\n");
            sip_log_err(sipAsciTempBuf);
            return 0;
        }
        else if ((sip->sipApiType == SIP_API_RES_MSG) 
        	     && (((hname_len == 12) && (strncmp (hname, "max-forwards", 12) == 0)) 
        	         || ((hname_len == 13) && (strncmp (hname, "proxy-require", 13) == 0)) 
        	         || ((hname_len == 5) && (strncmp (hname, "route", 5) == 0)) 
        	         || ((hname_len == 7) && (strncmp (hname, "require", 7) == 0)) 
//        	         || ((hname_len == 10) && (strncmp (hname, "user-agent", 10) == 0)) 
        	         || ((hname_len == 7) && (strncmp (hname, "subject", 7) == 0))
        	         || ((hname_len == 5) && (strncmp (hname, "event", 5) == 0))
        	         || ((hname_len == 8) && (strncmp (hname, "refer-to", 8) == 0))
        	         || ((hname_len == 18) && (strncmp (hname, "subscription-state", 18) == 0))))
        {
            sprintf((char *)sipAsciTempBuf, "sip response msg have req header\r\n");
            sip_log_err(sipAsciTempBuf);
            return 0;
        }

        if ((strncmp (hname, "refer-to", 8) == 0) && ((sip->sipApiMsg.sipMsg.sipReStruct.sipReHdrFlag[0] & SIP_HDR_REFER_TO_MASK) == SIP_HDR_REFER_TO_MASK))
        {
        	//sip_send_400();
            return -1;
        }

        if (sip_message_set_header(sip, hname, hvalue) < 0)
            return -1;

        return 0;
    }
    
    // Doesn't support multiple headers per line for the moment
    return 0;
}

int sip_msg_headers_parse(SIP_API_STRUCT *sip, char *buf, char **body)
{
    char    *colonIndex;
    char    hname[64];
    char    hvalue[256];
    char    *startOfHeader;
    char    *endOfHeader;
    char    *end;
    WORD    len;

    if ((sip == NULL) || (buf == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_msg_headers_parse: sip or buf is NULL\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    startOfHeader = buf;

    for (;;)
    {
        if (startOfHeader[0] == '\0')
        {
            sprintf((char *)sipAsciTempBuf, "SIP message does not end with CRLFCRLF\r\n");
            sip_log_err(sipAsciTempBuf);
            return 0;
        }

        if (sip_find_next_crlf(startOfHeader, &endOfHeader) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "End of header Not found\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        // the list of headers MUST always end with
        // CRLFCRLF (also CRCR and LFLF are allowed)
        if ((startOfHeader[0] == '\r') || (startOfHeader[0] == '\n'))
        {
            *body = startOfHeader;
            return 0;
        }

        // find the header name
        colonIndex = strchr(startOfHeader, ':');
        if (colonIndex == NULL)
        {
            sprintf((char *)sipAsciTempBuf, "colon Not found\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
        if (colonIndex - startOfHeader + 1 < 2)
            return -1;
        if (endOfHeader <= colonIndex)
        {
            sprintf((char *)sipAsciTempBuf, "Malformed message\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        if ((len = colonIndex - startOfHeader) > 64)
        {
            sprintf((char *)sipAsciTempBuf, "header name length out of range\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
            
        sip_clrncpy(hname, startOfHeader, len);
        
        // END of header is (end_of_header-2) if header separation is CRLF
        // END of header is (end_of_header-1) if header separation is CR or LF
        if ((endOfHeader[-2] == '\r') || (endOfHeader[-2] == '\n'))
            end = endOfHeader - 2;
        else
            end = endOfHeader - 1;
        if ((end - colonIndex) < 2)
            strcpy(hvalue, "");        // some headers (subject) can be empty
        else
        {
            if ((len = end - colonIndex - 1) > 256)
            {
                sprintf((char *)sipAsciTempBuf, "header value length out of range\r\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }

            sip_clrncpy(hvalue, colonIndex + 1, len);
        }
        
        // hvalue MAY contains multiple value. In this case, they
        // are separated by commas. But, a comma may be part of a
        // quoted-string ("here, and there" is an example where the
        // comma is not a separator!)
        if (sip_message_set_multiple_header(sip, hname, hvalue) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "End of header Not found\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        // continue on the next header
        startOfHeader = endOfHeader;
    }
    
    return -1;
}

int sip_msg_start_line_parse_req(SIP_MSG *dest, char *buf, char **nextHeader)
{
    char            *p1, *p2, *hp;
    char            tmp[256];
    SIP_START_LINE  *startLine;
    WORD            len;

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

    startLine = &dest->sipStartLine;
    *nextHeader = buf;
    
    // The first token is the method name
    p2 = strchr(buf, ' ');
    if (p2 == NULL)
        return -1;
    if (*(p2 + 1) == '\0' || *(p2 + 2) == '\0')
        return -1;
    if (p2 - buf == 0)
    {
        sprintf((char *)sipAsciTempBuf, "No space is allowed here\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if ((len = p2 - buf) > 256)
    {
        sprintf((char *)sipAsciTempBuf, "request method length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sip_clrncpy(tmp, buf, len);
    if (sip_method_api_conv(tmp, &startLine->sipMethod, SIP_STR_TO_API) < 0)
        return -2;
    
    // The second token is a sip-url or a uri
    p1 = strchr(p2 + 2, ' ');    // no space allowed inside sip-url
    if (p1 == NULL)
    {
        sprintf((char *)sipAsciTempBuf, "Uncompliant request-uri\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    if (p1 - p2 < 2)
        return -1;

    if ((len = p1 - p2 - 1) > 256)
    {
        sprintf((char *)sipAsciTempBuf, "request uri length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;       
    }
   
    sip_clrncpy(tmp, p2 + 1, len);
    if (sip_uri_parse(&startLine->requestUri, tmp) < 0)
        return -1;

    // find the the version and the beginning of headers
    hp = p1;
    while ((*hp != '\r') && (*hp != '\n'))
    {
        if (*hp)
            hp++;
        else
        {
            sprintf((char *)sipAsciTempBuf, "No crlf found\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if (hp - p1 < 2)
        return -1;

    if ((len = hp - p1 - 1) > 256)
    {
        sprintf((char *)sipAsciTempBuf, "request startLine version length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip_clrncpy(tmp, p1 + 1, len);

    if (sip_ver_api_conv(tmp, &startLine->sipVersion, SIP_STR_TO_API) < 0)
        return -1;

    hp++;

    if ((*hp) && ('\r' == hp[-1]) && ('\n' == hp[0]))
        hp++;

    (*nextHeader) = hp;
    
    return 0;
}

int sip_msg_start_line_parse_resp(SIP_MSG *dest, char *buf, char **nextHeader)
{
    char            *hp;
    char            tmp[128];
    char            *statuscode;
    char            *reasonphrase;
    BYTE            len;
    SIP_START_LINE  *startLine;

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

    startLine = &dest->sipStartLine;
    *nextHeader = buf;

    statuscode = strchr(buf, ' ');       // Search for first SPACE
    if (statuscode == NULL)
            return -1;

    if ((len = statuscode - buf) > 128)
    {
        sprintf((char *)sipAsciTempBuf, "response startLine vesion length out of range\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }
    
    sip_clrncpy(tmp, buf, len);
    
    if (sip_ver_api_conv(tmp, &startLine->sipVersion, SIP_STR_TO_API) < 0)
        return -1;

    reasonphrase = strchr(statuscode + 1, ' ');
    
    if (reasonphrase == NULL)
        return -1;

    if (sscanf(statuscode + 1, "%d", &startLine->statusCode) != 1)
        return -1;
    
    if (startLine->statusCode == 0)
        return -1;

    hp = reasonphrase;
    while ((*hp != '\r') && (*hp != '\n'))
    {
        if (*hp)
            hp++;
        else
        {
            sprintf((char *)sipAsciTempBuf, "No crlf found\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }

    if ((len = hp - reasonphrase - 1) > 128)
        len =128;

    sip_clrncpy(startLine->reasonPhrase, reasonphrase + 1, len);

    hp++;
    if ((*hp) && ('\r' == hp[-1]) && ('\n' == hp[0]))
        hp++;

    (*nextHeader) = hp;
    
    return 0;
}

int sip_msg_start_line_parse(SIP_API_STRUCT *dest, char *buf, char **nextHeader)
{
    int ret;

    if ((dest == NULL) || (buf == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_msg_start_line_parse: dest or buf is NULL\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1; 
    }
    
    if (strncmp(buf, "SIP/", 4) == 0)
    {
        dest->sipApiType = SIP_API_RES_MSG;
        if (sip_msg_start_line_parse_resp(&dest->sipApiMsg.sipMsg, buf, nextHeader) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "sip_msg_start_line_parse: parse resp failed\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1; 
        }
    }
    else
    {
        dest->sipApiType = SIP_API_REQ_MSG;
        if ((ret = sip_msg_start_line_parse_req(&dest->sipApiMsg.sipMsg, buf, nextHeader)) < 0)
        {
            if (ret == -2)
            {
                //sip_send_allow(buf);
            }
            sprintf((char *)sipAsciTempBuf, "sip_msg_start_line_parse: parse req failed\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
    }
    
    return dest->sipApiType;
}

int sip_sub_body_headers_pars(SIP_MESSAGE_BODYS *sipBodys, char *buf, char **body)
{
    char    *colonIndex;
    char    hname[64];
    char    hvalue[128];
    char    *startOfHeader;
    char    *endOfHeader;
    char    *end;
    BYTE    len;
    SIP_CONTENT_TYPE            *contentType;
    SIP_CONTENT_DISPOSITION *contentDisposition;

    if ((sipBodys == NULL) || (buf == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_sub_body_headers_pars: sipBodys or buf is NULL\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    startOfHeader = buf;

    for (;;)
    {
        if (startOfHeader[0] == '\0')
        {
            sprintf((char *)sipAsciTempBuf, "SIP message does not end with CRLFCRLF\r\n");
            sip_log_err(sipAsciTempBuf);
            return 0;
        }

        if (sip_find_next_crlf(startOfHeader, &endOfHeader) < 0)
        {
            sprintf((char *)sipAsciTempBuf, "End of header Not found\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        // the list of headers MUST always end with
        // CRLFCRLF (also CRCR and LFLF are allowed)
        if ((startOfHeader[0] == '\r') || (startOfHeader[0] == '\n'))
        {
            *body = startOfHeader;
            return 0;
        }

        // find the header name
        if ((colonIndex = strchr(startOfHeader, ':')) == NULL)
        {
            sprintf((char *)sipAsciTempBuf, "End of header Not found\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
        
        if (colonIndex - startOfHeader + 1 < 2)
            return -1;
        
        if (endOfHeader <= colonIndex)
        {
            sprintf((char *)sipAsciTempBuf, "Malformed message\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        len = colonIndex - startOfHeader;

        if (len > 64)
        {
            sprintf((char *)sipAsciTempBuf, "sub body header name length is too long\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        sip_clrncpy(hname, startOfHeader, len);
        
        // END of header is (end_of_header-2) if header separation is CRLF
        // END of header is (end_of_header-1) if header separation is CR or LF
        if ((endOfHeader[-2] == '\r') || (endOfHeader[-2] == '\n'))
            end = endOfHeader - 2;
        else
            end = endOfHeader - 1;

        if ((end - colonIndex) < 2)
            strcpy(hvalue, "");        // some headers (subject) can be empty
        else
        {
            len = end - colonIndex - 1;

            if (len > 128)
            {
                sprintf((char *)sipAsciTempBuf, "sub body header value length is too long\r\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }

            sip_clrncpy(hvalue, colonIndex + 1, len);
        }
        
        // hvalue MAY contains multiple value. In this case, they
        // are separated by commas. But, a comma may be part of a
        // quoted-string ("here, and there" is an example where the
        // comma is not a separator!)
        if ( (strcasecmp(hname, "c") == 0) || (strcasecmp(hname, "content-type") == 0))
        {
            contentType = &sipBodys->sipBody[sipBodys->sipBodyNum].sipBodyContentType;

            sip_content_type_parse(contentType, hvalue);

            sipBodys->sipBody[sipBodys->sipBodyNum].sipBodyHdrFlg[0] |= SIP_HDR_CONTENT_TYPE_MASK;
        }
        else if (strcasecmp(hname, "content-disposition") == 0)
        {
            contentDisposition = &sipBodys->sipBody[sipBodys->sipBodyNum].sipBodyContentDisposition;

            sip_content_disposition_parse(contentDisposition, hvalue);

            sipBodys->sipBody[sipBodys->sipBodyNum].sipBodyHdrFlg[0] |= SIP_HDR_CONTENT_DISPOSITION_MASK;
        }

        // continue on the next header
        startOfHeader = endOfHeader;
    }
    
    return -1;
}

int sip_sub_body_parse(SIP_MESSAGE_BODYS *sipBodys, char *buf, char *boundary)
{
    BYTE        boundaryLen;
    char        *subBody;
    char        *nextBoundary;
    char        endBoundary[64] = "";

    if ((buf == NULL) || (boundary == NULL) || (sipBodys == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "buff boundary or sipBodys is NULL\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

//  memset((BYTE *)sipBodys, 0, sizeof(SIP_MESSAGE_BODYS));

    subBody = buf;
    boundaryLen = strlen(boundary);
    sprintf(endBoundary, "%s--", boundary);

    if ((strncmp(subBody, boundary, boundaryLen) != 0)  
         || (strncmp(subBody, endBoundary, boundaryLen + 2) == 0) ||(strstr(subBody, endBoundary) == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "malformed message body\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    for (;;)
    {
        if (strncmp(subBody, endBoundary, boundaryLen + 2) == 0)
        {
            return 0;
        }

        while (('\r' != *subBody) && ('\n' != *subBody))
        {
            if (*subBody)
                subBody++;
            else
            {
                sprintf((char *)sipAsciTempBuf, "Final CRLF is missing\r\n");
                sip_log_err(sipAsciTempBuf);
                return -1;
            }
        }

        if (('\r' == subBody[0]) && ('\n' == subBody[1]))
            subBody = subBody + 2;
        else
            subBody = subBody + 1;

        if (((nextBoundary = strstr(subBody, boundary)) == NULL) 
        	|| (nextBoundary < subBody))
        {
            sprintf((char *)sipAsciTempBuf, "message end without boundary\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        sip_sub_body_headers_pars(sipBodys, subBody, &subBody);

        if (nextBoundary-subBody > SIP_MAX_BODY_LEN)
        {
            sprintf((char *)sipAsciTempBuf, "sub body message length is too long\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }

        sip_clrncpy((char *)sipBodys->sipBody[sipBodys->sipBodyNum].msgBody, subBody, nextBoundary-subBody);

        sipBodys->sipBodyNum++;

        subBody = nextBoundary;
    }
    
    return 0;
}

int sip_body_parse(SIP_API_STRUCT *sip, char *buf, WORD len)
{
    int                     i;
    char                    boundary[32];
    SIP_MESSAGE_BODYS       *sipBodys;
    SIP_CONTENT_TYPE        *contentType;
    WORD                    contentLength;

    if ((sip == NULL) || (buf == NULL))
    {
        sprintf((char *)sipAsciTempBuf, "sip_body_parse: sip or buf is NULL\r\n");
        sip_log_err(sipAsciTempBuf);
        return -1;
    }

    sipBodys = &sip->sipApiMsg.sipMsg.sipEntity.sipBodys;
    contentType = &sip->sipApiMsg.sipMsg.sipEntity.sipHdrContentType;
    contentLength = sip->sipApiMsg.sipMsg.sipEntity.sipHdrContentLength;

    if ((contentType->type == SIP_CONTENT_TYPE_APPLICATION) 
    	&& (contentType->subType == SIP_CONTENT_SUB_TYPE_SDP))
    {
        if (contentLength > len)
        {
            sprintf((char *)sipAsciTempBuf, "sip_body_parse:contentLength wrong\r\n");
            sip_log_err(sipAsciTempBuf);
            return -1;
        }
        
        strncpy((char *)sip->sipApiMsg.sipMsg.sipEntity.sipBodys.sipBody[0].msgBody, buf, contentLength + 2);
        sip->sipApiMsg.sipMsg.sipEntity.sipBodys.sipBodyNum = 1;
        
        return 0;
    }
    else if ((contentType->type == SIP_CONTENT_TYPE_APPLICATION) 
             && (contentType->subType == SIP_CONTENT_SUB_TYPE_ISUP))
    {
        if (contentLength > len)
            return -1;

        strncpy((char *)sip->sipApiMsg.sipMsg.sipEntity.sipBodys.sipBody[0].msgBody, buf, contentLength + 2);
        sip->sipApiMsg.sipMsg.sipEntity.sipBodys.sipBodyNum = 1;
        
        return 0;
    }
    else if ((contentType->type == SIP_CONTENT_TYPE_MULTIPART) 
             && (contentType->subType == SIP_CONTENT_SUB_TYPE_MIXED))
    {
        if (contentLength > len)
            return -1;

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

        sip_sub_body_parse(sipBodys, buf, boundary);
        
        return 0;
    }
    
    return -1;
}
