#include <stdio.h>
#include <string.h>
#include "./include/public.h"
#include "./include/pub_sdp.h"

/*@ignore@*/
void pub_replace_all_lws(char *msg)
{
	char *tmp;

	if (msg == NULL)
		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++;
            }
        }
    }
}

char *pub_strncpy(char *dest, const char *src, WORD length)
{
  	strncpy(dest, src, length);
  	dest[length] = '\0';
  	return dest;
}

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

  	*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') && (*sep != endSeparator))	// modify by megaco
    	return -1;                  // value must not end with this separator!
  	if (sep == buf)  
    	return -1;                  // empty value (or several space!)

  	pub_strncpy(dest, buf, sep - buf);

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

int pub_sdp_msg_init(PUB_SDP_MSG *sdp)
{
	if (sdp == NULL)
		return -1;
	
	memset((BYTE *)sdp, 0, sizeof(PUB_SDP_MSG));
	
	return 0;
}

int pub_sdp_net_type_conv(char *str, BYTE *netType, BYTE flag)
{
	if (flag == PUB_SDP_STR_TO_API)
	{
		if (strncmp(str, "IN", 2) == 0)
			*netType = PUB_SDP_NET_TYPE_IN;
		return 0;
	}
	else
	{
		switch (*netType)
		{
			case PUB_SDP_NET_TYPE_IN:
				strcpy(str, "IN");
				break;
			default:
				return -1;
		}
		return 0;
	}
	
	return -1;
}

int pub_sdp_addr_type_conv(char *str, BYTE *addrType, BYTE flag)
{
	if (flag == PUB_SDP_STR_TO_API)
	{
		if (strncmp(str, "IP4", 3) == 0)
			*addrType = PUB_SDP_ADDR_TYPE_IPV4;
		return 0;
	}
	else
	{
		switch (*addrType)
		{
			case PUB_SDP_ADDR_TYPE_IPV4:
				strcpy(str, "IP4");
				break;
			default:
				return -1;
		}
		return 0;
	}
	
	return -1;
}

int pub_sdp_attr_type_conv(char *str, BYTE *attrType, BYTE flag)
{
	int ret = 0;
	
	if (flag == PUB_SDP_STR_TO_API)
	{
		if (strncmp(str, "rtpmap", 6) == 0)
			*attrType = PUB_SDP_ATTR_TYPE_RTPMAP;
		else if (strncmp(str, "ptime", 5) == 0)
			*attrType = PUB_SDP_ATTR_TYPE_PTIME;
		else if (strncmp(str, "fmtp", 4) == 0)
			*attrType = PUB_SDP_ATTR_TYPE_FMTP;
		else if (strncmp(str, "T38FaxVersion", 13) == 0)
			*attrType = PUB_SDP_ATTR_TYPE_T38VER;
		else if (strncmp(str, "T38MaxBitRate", 13) == 0)
			*attrType = PUB_SDP_ATTR_TYPE_T38MBR;
		else if (strncmp(str, "ipbcp", 5) == 0)
			*attrType = PUB_SDP_ATTR_TYPE_IPBCP;
		else
		{
			ret = -2;
		}
		return ret;
	}
	else
	{
		switch (*attrType)
		{
			case PUB_SDP_ATTR_TYPE_RTPMAP:
				strcpy(str, "rtpmap");
				break;
			case PUB_SDP_ATTR_TYPE_PTIME:
				strcpy(str, "ptime");
				break;
			case PUB_SDP_ATTR_TYPE_FMTP:
				strcpy(str, "fmtp");
				break;
			case PUB_SDP_ATTR_TYPE_T38VER:
				strcpy(str, "T38FaxVersion");
				break;
			case PUB_SDP_ATTR_TYPE_T38MBR:
				strcpy(str, "T38MaxBitRate");
				break;
			case PUB_SDP_ATTR_TYPE_IPBCP:
				strcpy(str, "ipbcp");
				break;
			default:
				return -2;
		}
		return 0;
	}
	
	return -1;
}

int pub_sdp_media_type_conv(char *str, BYTE *mediaType, BYTE flag)
{
	if (flag == PUB_SDP_STR_TO_API)
	{
		if (strncmp(str, "audio", 6) == 0)
		{
			*mediaType = PUB_SDP_MEDIA_TYPE_AUDIO;
			return 0;
		}
		else if (strncmp(str, "video", 6) == 0)
		{
			*mediaType = PUB_SDP_MEDIA_TYPE_VIDEO;
			return 0;
		}
		else if (strncmp(str, "image", 6) == 0)
		{
			*mediaType = PUB_SDP_MEDIA_TYPE_IMAGE;
			return 0;
		}
		else
			return -2;
	}
	else
	{
		switch (*mediaType)
		{
			case PUB_SDP_MEDIA_TYPE_AUDIO:
				strcpy(str, "audio");
				break;
			case PUB_SDP_MEDIA_TYPE_VIDEO:
				strcpy(str, "video");
				break;
			case PUB_SDP_MEDIA_TYPE_IMAGE:
				strcpy(str, "image");
				break;
			default:
				return -1;
		}
		return 0;
	}
	
	return -1;
}

int pub_sdp_proto_type_conv(char *str, BYTE *protoType, BYTE flag)
{
	if (flag == PUB_SDP_STR_TO_API)
	{
		if (strncmp(str, "RTP/AVP", 7) == 0)
			*protoType = PUB_SDP_PROTO_TYPE_RTP_AVP;
		else if (strncmp(str, "udptl", 5) == 0)
		{
			*protoType = PUB_SDP_PROTO_TYPE_IMAGE_UDPTL;
			return -2;
		}

		return 0;
	}
	else
	{
		switch (*protoType)
		{
			case PUB_SDP_PROTO_TYPE_RTP_AVP:
				strcpy(str, "RTP/AVP");
				break;
			case PUB_SDP_PROTO_TYPE_IMAGE_UDPTL:
				strcpy(str, "udptl t38");
				break;
			default:
				return -1;
		}
		return 0;
	}
	
	return -1;
}

int pub_sdp_parse_v(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char 	*equal;
  	char 	*crlf;
	char	value[8];
	
  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	if (equal == buf)
    	return -1;

  	// check if header is "v"
  	if (equal[-1] != 'v')
	    return -2;

  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
    if ((flag & PUB_SDP_FLAG_V) == PUB_SDP_FLAG_V)
    {
  		pub_strncpy(value, equal + 1, crlf - (equal + 1));
		sdp->v.value = atoi(value);
	}
	
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
//    printf("v: %d\n", sdp->v.value);
    
    sdp->flag |= PUB_SDP_FLAG_V;
    
  	return 0;
}

int pub_sdp_parse_o(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;
  	char *tmp;
 	char *tmpNext;
 	char value[16];
  	int i;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	// check if header is "o"
  	if (equal[-1] != 'o')
    	return -2;

  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           /* o=\r ?? bad header */
	
	if ((flag & PUB_SDP_FLAG_V) == PUB_SDP_FLAG_V)
	{
	  	tmp = equal + 1;
	  	// o=username sess-id sess-version nettype addrtype addr
	  	// useranme can contain any char (ascii) except "space" and CRLF
	  	if (pub_set_next_token(sdp->o.userName, tmp, ' ', &tmpNext) < 0)
	        return -1;
	  	tmp = tmpNext;
	
	  	// sess_id contains only numeric characters
	  	if (pub_set_next_token(sdp->o.sessId, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	  	tmp = tmpNext;
	
	  	// sess_version contains only numeric characters
	  	if (pub_set_next_token (sdp->o.sessVer, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	  	tmp = tmpNext;
	
	  	// nettype is "IN" but will surely be extented!!! assume it's some alpha-char
	  	if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	    if (pub_sdp_net_type_conv(value, &sdp->o.netType, PUB_SDP_STR_TO_API) < 0)
	    	return -1;
	  	tmp = tmpNext;
		
	  	// addrtype  is "IP4" or "IP6" but will surely be extented!!!
	  	if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	    if (pub_sdp_addr_type_conv(value, &sdp->o.addrType, PUB_SDP_STR_TO_API) < 0)
	    	return -1;
	  	tmp = tmpNext;
		
	  	// addr  is "IP4" or "IP6" but will surely be extented!!!
	  	i = pub_set_next_token(sdp->o.addr, tmp, '\r', &tmpNext);
	  	if (i != 0)
	    {                           /* could it be "\n" only??? rfc says to accept CR or LF instead of CRLF */
	      	if (pub_set_next_token(sdp->o.addr, tmp, '\n', &tmpNext) < 0)
	        	return -1;
	    }
	}
	
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
  	
//  	printf("o: %s, %s, %s, %d, %d, %s\n", sdp->o.userName, sdp->o.sessId, sdp->o.sessVer, sdp->o.netType, sdp->o.addrType, sdp->o.addr);
  	
  	sdp->flag |= PUB_SDP_FLAG_O;
  	
  	return 0;
}

int pub_sdp_parse_s(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	// check if header is "s"
  	if (equal[-1] != 's')
    	return -2;

  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // o=\r ?? bad header

	if ((flag & PUB_SDP_FLAG_S) == PUB_SDP_FLAG_S)
  		pub_strncpy(sdp->s.sessName, equal + 1, crlf - (equal + 1));

  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
//    printf("s: %s\n", sdp->s.sessName);
    
    sdp->flag |= PUB_SDP_FLAG_S;
    
  	return 0;
}

int pub_sdp_parse_i(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	// check if header is "i"
  	if (equal[-1] != 'i')
    	return -2;

  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // o=\r ?? bad header

	if ((flag & PUB_SDP_FLAG_I) == PUB_SDP_FLAG_I)
  		pub_strncpy(sdp->i.info, equal + 1, crlf - (equal + 1));

  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
//    printf("i: %s\n", sdp->i.info);
    
    if (sdp->medias.num == 0)
    	sdp->flag |= PUB_SDP_FLAG_I;
    else
    	sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_I;
    
  	return 0;
}

int pub_sdp_parse_u(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
	    equal++;
	if (*equal == '\0')
	    return -1;
	
	// check if header is "u"
	if (equal[-1] != 'u')
	   	return -2;
	
	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
  	return 0;
}

int pub_sdp_parse_e(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
	    equal++;
	if (*equal == '\0')
	    return -1;
	
	// check if header is "e"
	if (equal[-1] != 'e')
	   	return -2;
	
	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
  	return 0;
}

int pub_sdp_parse_p(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
	    equal++;
	if (*equal == '\0')
	    return -1;
	
	// check if header is "p"
	if (equal[-1] != 'p')
	   	return -2;
	
	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
  	return 0;
}

int pub_sdp_parse_c(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;
  	char *tmp;
  	char *tmpNext;
  	char value[16];
  	char *slash;
  	PUB_SDP_C *cHeader;
  	int i;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
 	if (*equal == '\0')
    	return -1;

  	// check if header is "c"
  	if (equal[-1] != 'c')
    	return -2;

  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // c=\r ?? bad header
	
	if ((flag & PUB_SDP_FLAG_C) == PUB_SDP_FLAG_C)
	{
	  	tmp = equal + 1;
	  	
	  	// c=nettype addrtype (multicastaddr | addr)
	
	  	// nettype is "IN" and will be extended
	  	if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	    if (pub_sdp_net_type_conv(value, &sdp->c.netType, PUB_SDP_STR_TO_API) < 0)
		    return -1;
	  	tmp = tmpNext;
	
	  	// nettype is "IP4" or "IP6" and will be extended
	  	if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	    if (pub_sdp_addr_type_conv(value, &sdp->c.addrType, PUB_SDP_STR_TO_API) < 0)
		    return -1;
	  	tmp = tmpNext;
	
	  	/* there we have a multicast or unicast address */
	  	/* multicast can be ip/ttl [/integer] */
	  	/* unicast is FQDN or ip (no ttl, no integer) */
	
	    slash = strchr (tmp, '/');
		cHeader = &sdp->c;
		
	    if (slash != NULL && slash < crlf)  // it's a multicast address!
	    {
	    	// Not supported for the moment
	    }
	    else
	    {
	        // in this case, we have a unicast address
	        i = pub_set_next_token(cHeader->addr, tmp, '\r', &tmpNext);
	        if (i != 0)
	        {
	            if (pub_set_next_token(cHeader->addr, tmp, '\n', &tmpNext) < 0)
	                return -1;
	        }
	    }
	}
	
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
  	
//  	printf("c: %d, %d, %s\n", sdp->c.netType, sdp->c.addrType, sdp->c.addr);
  	
  	if (sdp->medias.num == 0)
    	sdp->flag |= PUB_SDP_FLAG_C;
    else
    	sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_C;
  	
  	return 0;
}

int pub_sdp_parse_m_c(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;
  	char *tmp;
  	char *tmpNext;
  	char value[16];
  	char *slash;
  	PUB_SDP_C *cHeader;
  	int i;

  	*next = buf;
  	equal = buf;

	if (sdp->medias.num == 0)
		return -1;
  
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
 	if (*equal == '\0')
    	return -1;

  	// check if header is "c"
  	if (equal[-1] != 'c')
    	return -2;

  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // c=\r ?? bad header
	
	if ((flag & PUB_SDP_FLAG_C) == PUB_SDP_FLAG_C)
	{
	  	tmp = equal + 1;
	  	
	  	// c=nettype addrtype (multicastaddr | addr)
	
	  	// nettype is "IN" and will be extended
	  	if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	    if (pub_sdp_net_type_conv(value, &sdp->medias.medias[sdp->medias.num - 1].c.netType, PUB_SDP_STR_TO_API) < 0)
		    return -1;
	  	tmp = tmpNext;
	
	  	// nettype is "IP4" or "IP6" and will be extended
	  	if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	    if (pub_sdp_addr_type_conv(value, &sdp->medias.medias[sdp->medias.num - 1].c.addrType, PUB_SDP_STR_TO_API) < 0)
		    return -1;
	  	tmp = tmpNext;
	
	  	/* there we have a multicast or unicast address */
	  	/* multicast can be ip/ttl [/integer] */
	  	/* unicast is FQDN or ip (no ttl, no integer) */
	
	    slash = strchr (tmp, '/');
		cHeader = &sdp->medias.medias[sdp->medias.num - 1].c;
		
	    if (slash != NULL && slash < crlf)  // it's a multicast address!
	    {
	    	// Not supported for the moment
	    }
	    else
	    {
	        // in this case, we have a unicast address
	        i = pub_set_next_token(cHeader->addr, tmp, '\r', &tmpNext);
	        if (i != 0)
	        {
	            if (pub_set_next_token(cHeader->addr, tmp, '\n', &tmpNext) < 0)
	                return -1;
	        }
	    }
	}
	
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
  	
//  	printf("c: %d, %d, %s\n", sdp->c.netType, sdp->c.addrType, sdp->c.addr);
  	
    	sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_C;
  	
  	return 0;
}

int pub_sdp_parse_b(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
	    equal++;
	if (*equal == '\0')
	    return -1;
	
	// check if header is "b"
	if (equal[-1] != 'b')
	   	return -2;
	
	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
  	return 0;
}

int pub_sdp_parse_t(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;
  	char *tmp;
  	char *tmpNext;
  	char value[16];
  	int i;
 	PUB_SDP_T *tHeader;

  	*next = buf;
 	equal = buf;
 	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	// check if header is "t"
  	if (equal[-1] != 't')
    	return -2;

 	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           /* t=\r ?? bad header */
	
	if ((flag & PUB_SDP_FLAG_T) == PUB_SDP_FLAG_T)
	{
	  	tmp = equal + 1;
	  	// t = start_time stop_time
		tHeader = &sdp->t;
		
	  	if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)	
	      	return -1;
	    tHeader->startTime = atoi(value);  
	  	tmp = tmpNext;
	
	  	i = pub_set_next_token(value, tmp, '\r', &tmpNext);
	  	if (i != 0)
	    {
	      	if (pub_set_next_token(value, tmp, '\n', &tmpNext) < 0)
	          return -1;
	        tHeader->stopTime = atoi(value);
	    }
		else
		{
			tHeader->stopTime = atoi(value);
		}
	}
	
	if (crlf[1] == '\n')
   		*next = crlf + 2;
  	else
    	*next = crlf + 1;
  	
//  	printf("t: %ld, %ld\n", sdp->t.startTime, sdp->t.stopTime);
  	
  	sdp->flag |= PUB_SDP_FLAG_T;
  	
  	return 0;
}

int pub_sdp_parse_r(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
	    equal++;
	if (*equal == '\0')
	    return -1;
	
	// check if header is "r"
	if (equal[-1] != 'r')
	   	return -2;
	
	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
  	return 0;
}

int pub_sdp_parse_z(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
	    equal++;
	if (*equal == '\0')
	    return -1;
	
	// check if header is "z"
	if (equal[-1] != 'z')
	   	return -2;
	
	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
  	return 0;
}

int pub_sdp_parse_k(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
	    equal++;
	if (*equal == '\0')
	    return -1;
	
	// check if header is "k"
	if (equal[-1] != 'k')
	   	return -2;
	
	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           // v=\r ?? bad header
    
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
  	return 0;
}

int pub_sdp_parse_a(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;
  	char *tmp;
  	char *tmpNext;
  	char value[32];
  	int i, ret;
  	//BYTE num, mediaNum;
  	PUB_SDP_A *a;
  	char *colon;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	// check if header is "a"
  	if (equal[-1] != 'a')
    	return -2;
	
  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           /* a=\r ?? bad header */
	
	if ((flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
	{
	  	tmp = equal + 1;
		a = &sdp->a;
	  	// a=att-field[:att-value]
	
	  	// is there any att-value?
	  	colon = strchr (equal + 1, ':');
	  	if ((colon != NULL) && (colon < crlf))
	    {
	      	// att-field is alpha-numeric
	    	if (pub_set_next_token(value, tmp, ':', &tmpNext) < 0)
	          	return -1;
	        if ((ret = pub_sdp_attr_type_conv(value, &a->aType, PUB_SDP_STR_TO_API)) == -1)
	        	return -1;
	        else if (ret == -2)
	        {
	        	if (crlf[1] == '\n')
    				*next = crlf + 2;
  				else
    				*next = crlf + 1;
    			return 0;
    		}
	      	tmp = tmpNext;
	
	      	i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);
	      	if (i != 0)
	        {
	          	if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
	              	return -1;
	        }
	  	}
	  	else
	    {
	      	i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);
	      	if (i != 0)
	        {
	          	if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
	              	return -1;
	        }
	    }
	    sdp->medias.medias[sdp->medias.num - 1].attrs.num++;
	}
	
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
  	
//  	printf("a: %d, %s\n", a->aType, a->aValue);
 
    	sdp->flag |= PUB_SDP_FLAG_A;
  	
  	return 0;
}

int pub_sdp_parse_m(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;
  	char *tmp;
  	char *tmpNext;
  	char value[32];
  	int i;
  	PUB_SDP_M *mHeader;
  	BYTE num;
  	char *slash;
  	char *space;
	int moreSpace;
	int ret;
	
  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	// check if header is "m"
  	if (equal[-1] != 'm')
    	return -2;

  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           /* a=\r ?? bad header */
	
	if ((flag & PUB_SDP_FLAG_M) == PUB_SDP_FLAG_M)
	{
	  	tmp = equal + 1;
		num = sdp->medias.num;
		mHeader = &sdp->medias.medias[num].m;
	  	// m=media port ["/"integer] proto *(payload_number)
	  	// media is "audio" "video" "application" "data" or other...
	  	if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
	    	return -1;
	    if ((ret = pub_sdp_media_type_conv(value, &mHeader->media, PUB_SDP_STR_TO_API)) < 0)
	    {
	    	if (-2 == ret)
	    	{	
			  	if (crlf[1] == '\n')
			    	*next = crlf + 2;
			  	else
			    	*next = crlf + 1;
			    		    	
	    		return 0;
	    	}
	    		
		    return -1;
		}
	  	tmp = tmpNext;
	
	  	slash = strchr (tmp, '/');
	  	space = strchr (tmp, ' ');
	  	if ((slash != NULL) && (slash < space))
	    {                           /* a number of port is specified! */
	      	if (pub_set_next_token(value, tmp, '/', &tmpNext) < 0)
	          	return -1;
	        mHeader->port = atoi(value);
	      	tmp = tmpNext;
	
	        if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
	          	return -1;
	        mHeader->portNum = atoi(value);
	      	tmp = tmpNext;
	  	}
	  	else
	    {
	      	if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
	          	return -1;
	        mHeader->port = atoi(value);
	      	tmp = tmpNext;
	    }
	
	  	if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
	    	return -1;

	    if ((ret = pub_sdp_proto_type_conv(value, &mHeader->proto, PUB_SDP_STR_TO_API)) < 0)
	    {
               if (ret == -2)
               {
                   if (crlf[1] == '\n')
                       *next = crlf + 2;
                   else
                       *next = crlf + 1;

                   sdp->medias.medias[sdp->medias.num].flag |= PUB_SDP_FLAG_M;
                   sdp->flag |= PUB_SDP_FLAG_M;
                   sdp->medias.num++;

                   return 0;
               }

               return -1;
	    }

		tmp = tmpNext;
	
	    space = strchr(tmp + 1, ' ');
	    if (space == NULL)
	      	moreSpace = 1;
	    else if ((space != NULL) && (space > crlf))
	      	moreSpace = 1;
	    else
	      	moreSpace = 0;
	    while(moreSpace == 0)
	    {
	        if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
	            return -1;
	        mHeader->payloads[mHeader->plNum++] = atoi(value);
	        tmp = tmpNext;
	
	        space = strchr(tmp + 1, ' ');
	        if (space == NULL)
	          	moreSpace = 1;
	        else if ((space != NULL) && (space > crlf))
	          	moreSpace = 1;
	        else
	          	moreSpace = 0;
	    }
	    if (tmpNext < crlf)
	    {                         // tmpNext is still less than clrf: no space
	        i = pub_set_next_token(value, tmp, '\r', &tmpNext);
	        if (i != 0)
	        {
	            if (pub_set_next_token(value, tmp, '\n', &tmpNext) < 0)
	                return -1;
	        }
	        mHeader->payloads[mHeader->plNum++] = atoi(value);
	  	}
	}
	
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
    
//    printf("m: %d, %d, %d, %d, %d, %d, %d\n", mHeader->media, mHeader->port, mHeader->portNum, mHeader->proto, mHeader->plNum, mHeader->payloads[0], mHeader->payloads[1]);
    
    sdp->medias.medias[sdp->medias.num].flag |= PUB_SDP_FLAG_M;
    sdp->flag |= PUB_SDP_FLAG_M;
    sdp->medias.num++;
    
  	return 0;
}

int pub_sdp_parse_m_a(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char *equal;
  	char *crlf;
  	char *tmp;
  	char *tmpNext;
  	char value[32];
  	int i, ret;
  	BYTE num, mediaNum;
  	PUB_SDP_A *a;
  	char *colon;

  	*next = buf;
  	equal = buf;
  	
  	while ((*equal != '=') && (*equal != '\0'))
    	equal++;
  	if (*equal == '\0')
    	return -1;

  	// check if header is "a"
  	if (equal[-1] != 'a')
    	return -2;
	
  	crlf = equal + 1;
	
  	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
    	crlf++;
  	if (*crlf == '\0')
    	return -1;
  	if (crlf == equal + 1)
    	return -1;           /* a=\r ?? bad header */
	
	if ((flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
	{
	  	tmp = equal + 1;
	  	mediaNum = sdp->medias.num;
	  	num = sdp->medias.medias[mediaNum - 1].attrs.num;
		a = &sdp->medias.medias[mediaNum - 1].attrs.attrs[num];
		
	  	// a=att-field[:att-value]
	
	  	// is there any att-value?
	  	colon = strchr (equal + 1, ':');
	  	if ((colon != NULL) && (colon < crlf))
	    {
	      	// att-field is alpha-numeric
	    	if (pub_set_next_token(value, tmp, ':', &tmpNext) < 0)
	          	return -1;
	        if ((ret = pub_sdp_attr_type_conv(value, &a->aType, PUB_SDP_STR_TO_API)) == -1)
	        	return -1;
	        else if (ret == -2)
	        {
	        	if (crlf[1] == '\n')
    				*next = crlf + 2;
  				else
    				*next = crlf + 1;
    			return 0;
    		}
	      	tmp = tmpNext;
	
	      	i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);
	      	if (i != 0)
	        {
	          	if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
	              	return -1;
	        }
	  	}
	  	else
	    {
	      	i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);
	      	if (i != 0)
	        {
	          	if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
	              	return -1;
	        }
	    }
	    sdp->medias.medias[sdp->medias.num - 1].attrs.num++;
	}
	
  	if (crlf[1] == '\n')
    	*next = crlf + 2;
  	else
    	*next = crlf + 1;
  	
//  	printf("a: %d, %s\n", a->aType, a->aValue);
  	
	if (sdp->medias.num == 0)
		sdp->flag |= PUB_SDP_FLAG_A;
	else
		sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_A;
  	
  	return 0;
}

int pub_sdp_check_ending(char *ptr, char **nextbuf)
{
	*nextbuf = ptr;
	
	if ((*ptr == '\0') || (*ptr == '\r') || (*ptr == '\n'))
	{	
        return 0;
    }
    else if (((ptr[0] == '.') && (ptr[1] == '\r') && (ptr[2] == '\n')))
    {
        *nextbuf = ptr + 3;
        return 1;   
    }
    else
    	return -1;	   
}

int pub_sdp_parse(PUB_SDP_MSG *sdp, char *buf, char **nextMsg, DWORD flag)
{
  	// In SDP, headers must be in the right order
  	/* This is a simple example
	     v=0
	     o=user1 53655765 2353687637 IN IP4 128.3.4.5
	     s=Mbone Audio
	     i=Discussion of Mbone Engineering Issues
	     e=mbone@somewhere.com
	     c=IN IP4 224.2.0.1/127
	     t=0 0
	     m=audio 3456 RTP/AVP 0
	     a=rtpmap:0 PCMU/8000
   	*/

  	char 	*nextBuf;
  	char 	*ptr;
	int 	i;
	int     ret;
	int 	moreHeader = 1;
	
	pub_sdp_msg_init(sdp);
	
  	ptr = (char *) buf;
  	
  	// mandatory
  	if (pub_sdp_parse_v(sdp, ptr, &nextBuf, flag) == -1)
  		return -1;
  	ptr = nextBuf;
	
	// mandatory
	if (pub_sdp_parse_o(sdp, ptr, &nextBuf, flag) == -1)
  		return -1;
  	ptr = nextBuf;
  	
  	// mandatory
  	if (pub_sdp_parse_s(sdp, ptr, &nextBuf, flag) == -1)
  		return -1;
  	ptr = nextBuf;
	
	// optional
  	if (pub_sdp_parse_i(sdp, ptr, &nextBuf, flag) == -1)
  		return -1;
  	ptr = nextBuf;
	
	// optional
  	if (pub_sdp_parse_u(sdp, ptr, &nextBuf, flag) == -1)
  		return -1;
  	ptr = nextBuf;
	
	// optional
  	i = 0;
  	while (i == 0)
    {
      	if ((i = pub_sdp_parse_e(sdp, ptr, &nextBuf, flag)) == -1)
      		return -1;
      	ptr = nextBuf;
    }
    
    // optional
  	i = 0;
  	while (i == 0)
    {
      	if ((i = pub_sdp_parse_p(sdp, ptr, &nextBuf, flag)) == -1)
      		return -1;
      	ptr = nextBuf;
    }
	
	// optional
  	if (pub_sdp_parse_c(sdp, ptr, &nextBuf, flag) == -1)
  		return -1;
  	ptr = nextBuf;
	
	// optional
  	i = 0;
 	while (i == 0)
    {
      	if ((i = pub_sdp_parse_b(sdp, ptr, &nextBuf, flag)) == -1)
      		return -1;
      	ptr = nextBuf;
    }
	
	// mandatory
  	if (pub_sdp_parse_t(sdp, ptr, &nextBuf, flag) == -1)
  		return -1;
  	
	
  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
  	{
  		*nextMsg = nextBuf;
  		return ret;
  	}
  	
  	ptr = nextBuf;

	
	// optional
  	i = 0;
  	while (i == 0)
    {
      	if ((i = pub_sdp_parse_r(sdp, ptr, &nextBuf, flag)) == -1)
      		return -1;
      	
	  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	  	{
	  		*nextMsg = nextBuf;
	  		return ret;
	  	}
	  	ptr = nextBuf;
    }
	
	// optional
    if (pub_sdp_parse_t(sdp, ptr, &nextBuf, flag) == -1)
    	return -1;
	  	
	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	{
	    *nextMsg = nextBuf;
	  	return ret;
	}
	ptr = nextBuf;

    while (moreHeader == 1)
    {
        i = 0;
        while (i == 0)          // is a "r" header
        {
            if ((i = pub_sdp_parse_r(sdp, ptr, &nextBuf, flag)) == -1)
            	return -1;
		  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
		  	{
		  		*nextMsg = nextBuf;
		  		return ret;
		  	}
		  	ptr = nextBuf;
        }

        if ((i = pub_sdp_parse_t(sdp, ptr, &nextBuf, flag)) == -1)
        	return -1;
        else if (i == -2)
        	moreHeader = 0;	// no more "t" headers
        else
          	moreHeader = 1;
	  	
	  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	  	{
	  		*nextMsg = nextBuf;
	  		return ret;
	  	}
	  	ptr = nextBuf;
   	}
	
	// optional
  	if (pub_sdp_parse_z(sdp, ptr, &nextBuf, flag) == -1)
    	return -1;
	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	{
	    *nextMsg = nextBuf;
	    return ret;
	}
	ptr = nextBuf;
	
	// optional
  	if (pub_sdp_parse_k(sdp, ptr, &nextBuf, flag) == -1)
    	return -1;
  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
  	{
  		*nextMsg = nextBuf;
  		return ret;
  	}
  	ptr = nextBuf;
	
	// optional
  	// 0 or more "a" header
  	i = 0;
  	while (i == 0)                // no more "a" header
    {
      	if ((i = pub_sdp_parse_a(sdp, ptr, &nextBuf, flag)) == -1)
        	return -1;
	  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	  	{
	  		*nextMsg = nextBuf;
	  		return ret;
	  	}
	  	ptr = nextBuf;
    }
    
    moreHeader = 0;
    while (moreHeader == 0)
    {
        // optional
        if ((moreHeader = pub_sdp_parse_m(sdp, ptr, &nextBuf, flag)) == -1)
        	return -1;
        else if (moreHeader == -2)
        	break;
        
	  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	  	{
	  		*nextMsg = nextBuf;
	  		return ret;
	  	}
	  	ptr = nextBuf;
		
		// optional
        if (pub_sdp_parse_i (sdp, ptr, &nextBuf, flag) == -1)
          	return -1;
	  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	  	{
	  		*nextMsg = nextBuf;
	  		return ret;
	  	}
	  	ptr = nextBuf;
		
		// optional
        i = 0;
        while (i == 0)
        {
            if ((i = pub_sdp_parse_m_c(sdp, ptr, &nextBuf, flag)) == -1)
              	return -1;
		  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
		  	{
		  		*nextMsg = nextBuf;
		  		return ret;
		  	}
		  	ptr = nextBuf;
        }
		
		// optional
        i = 0;
        while (i == 0)
        {
            if ((i = pub_sdp_parse_b(sdp, ptr, &nextBuf, flag)) == -1)
              	return -1;
		  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
		  	{
		  		*nextMsg = nextBuf;
		  		return ret;
		  	}
		  	ptr = nextBuf;
        }
        
        // optional
        if (pub_sdp_parse_k(sdp, ptr, &nextBuf, flag) == -1)
          	return -1;
	  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
	  	{
	  		*nextMsg = nextBuf;
	  		return ret;
	  	}
	  	ptr = nextBuf;
		
		// optional
        i = 0;
        while (i == 0)
        {
            if ((i = pub_sdp_parse_m_a(sdp, ptr, &nextBuf, flag)) == -1)
              	return -1;
		  	if ((ret = pub_sdp_check_ending(nextBuf, &nextBuf)) >= 0)
		  	{
		  		*nextMsg = nextBuf;
		  		return ret;
		  	}
		  	ptr = nextBuf;
        }
    }

  	return 0;
}


//parse sdp for megaco

int pub_sdp_parse_find_end_for_megaco(char *start, char **end)
{
	int		get_char_times = 0;
	char		*temp = start;
	char		*ending;
	char		*equal;

	if ((equal = strchr(temp, '=')) == NULL)
	{
		while (*temp != '\0')
			temp++;

		do
		{
			temp--;
		}
		while (*temp == ' ');

		*end = temp + 1;
	}
	else
	{
		if (*(equal - 2) != ' ')
		{
			if ((equal = strchr(equal + 1, '=')) == NULL)
			{
				while (*equal!= '\0')
					equal++;

				do
				{
					equal--;
				}
				while (*equal == ' ');

				*end = equal + 1;

				return 0;
			}
		}

		ending = equal;

		for (;;)
		{
			ending--;

			if (*ending != ' ')
			{
				get_char_times++;

				if (get_char_times == 1)
					ending--;
			}

			if (get_char_times == 2)
				break;

			if (ending < start)
				break;

		}

		if (ending < start)
			return -1;
		else
			*end = ending + 1;
	}

	return 0;
}

int pub_sdp_parse_v_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char 	*equal;
	char 	*crlf;
	char		value[8];

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	if (equal == buf)
		return -1;

	// check if header is "v"
	if (equal[-1] != 'v')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

  	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if ((flag & PUB_SDP_FLAG_V) == PUB_SDP_FLAG_V)
	{
		pub_strncpy(value, equal + 1, crlf - (equal + 1));
		sdp->v.value = atoi(value);
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//    printf("v: %d\n", sdp->v.value);

	sdp->flag |= PUB_SDP_FLAG_V;

  	return 0;
}

int pub_sdp_parse_o_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;
	char		*tmp;
	char		*tmpNext;
	char		value[16];
	int		i;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;
	if (*equal == '\0')
		return -1;

	// check if header is "o"
	if (equal[-1] != 'o')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           /* o=\r ?? bad header */

	if ((flag & PUB_SDP_FLAG_V) == PUB_SDP_FLAG_V)
	{
		tmp = equal + 1;
		// o=username sess-id sess-version nettype addrtype addr
		// useranme can contain any char (ascii) except "space" and CRLF
		if (pub_set_next_token(sdp->o.userName, tmp, ' ', &tmpNext) < 0)
			return -1;

		tmp = tmpNext;

	  	// sess_id contains only numeric characters
		if (pub_set_next_token(sdp->o.sessId, tmp, ' ', &tmpNext) < 0)
			return -1;

		tmp = tmpNext;

		// sess_version contains only numeric characters
		if (pub_set_next_token (sdp->o.sessVer, tmp, ' ', &tmpNext) < 0)
			return -1;

		tmp = tmpNext;

		// nettype is "IN" but will surely be extented!!! assume it's some alpha-char
		if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
			return -1;
		if (pub_sdp_net_type_conv(value, &sdp->o.netType, PUB_SDP_STR_TO_API) < 0)
			return -1;

		tmp = tmpNext;

		// addrtype  is "IP4" or "IP6" but will surely be extented!!!
		if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
			return -1;
		if (pub_sdp_addr_type_conv(value, &sdp->o.addrType, PUB_SDP_STR_TO_API) < 0)
			return -1;

		tmp = tmpNext;

		// addr  is "IP4" or "IP6" but will surely be extented!!!
		i = pub_set_next_token(sdp->o.addr, tmp, '\r', &tmpNext);
		if (i != 0)
		{                           /* could it be "\n" only??? rfc says to accept CR or LF instead of CRLF */
			if (pub_set_next_token(sdp->o.addr, tmp, '\n', &tmpNext) < 0)
				return -1;
		}
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//  	printf("o: %s, %s, %s, %d, %d, %s\n", sdp->o.userName, sdp->o.sessId, sdp->o.sessVer, sdp->o.netType, sdp->o.addrType, sdp->o.addr);

	sdp->flag |= PUB_SDP_FLAG_O;

	return 0;
}

int pub_sdp_parse_s_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "s"
	if (equal[-1] != 's')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // o=\r ?? bad header

	if ((flag & PUB_SDP_FLAG_S) == PUB_SDP_FLAG_S)
		pub_strncpy(sdp->s.sessName, equal + 1, crlf - (equal + 1));

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//    printf("s: %s\n", sdp->s.sessName);

	sdp->flag |= PUB_SDP_FLAG_S;

	return 0;
}

int pub_sdp_parse_i_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "i"
	if (equal[-1] != 'i')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;
	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // o=\r ?? bad header

	if ((flag & PUB_SDP_FLAG_I) == PUB_SDP_FLAG_I)
		pub_strncpy(sdp->i.info, equal + 1, crlf - (equal + 1));

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//    printf("i: %s\n", sdp->i.info);

	if (sdp->medias.num == 0)
		sdp->flag |= PUB_SDP_FLAG_I;
	else
		sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_I;


	return 0;
}

int pub_sdp_parse_u_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

  	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "u"
	if (equal[-1] != 'u')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

	return 0;
}

int pub_sdp_parse_e_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "e"
	if (equal[-1] != 'e')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

	return 0;
}

int pub_sdp_parse_p_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "p"
	if (equal[-1] != 'p')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

	return 0;
}

int pub_sdp_parse_c_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
  	char				*equal;
  	char				*crlf;
  	char				*tmp;
  	char				*tmpNext;
  	char				value[16];
  	char				*slash;
  	PUB_SDP_C		*cHeader;
  	int				i;

	*next = buf;
	equal = buf;
  	
	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "c"
	if (equal[-1] != 'c')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // c=\r ?? bad header

	if ((flag & PUB_SDP_FLAG_C) == PUB_SDP_FLAG_C)
	{
		tmp = equal + 1;
  	
		// c=nettype addrtype (multicastaddr | addr)
	  	// nettype is "IN" and will be extended
		if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
			return -1;

		if (pub_sdp_net_type_conv(value, &sdp->c.netType, PUB_SDP_STR_TO_API) < 0)
			return -1;

		tmp = tmpNext;

		// nettype is "IP4" or "IP6" and will be extended
		if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
			return -1;

		if (pub_sdp_addr_type_conv(value, &sdp->c.addrType, PUB_SDP_STR_TO_API) < 0)
			return -1;

		tmp = tmpNext;

		/* there we have a multicast or unicast address */
		/* multicast can be ip/ttl [/integer] */
		/* unicast is FQDN or ip (no ttl, no integer) */

		slash = strchr (tmp, '/');
		cHeader = &sdp->c;

		if (slash != NULL && slash < crlf)  // it's a multicast address!
		{
			// Not supported for the moment
		}
		else
		{
			// in this case, we have a unicast address
			i = pub_set_next_token(cHeader->addr, tmp, '\r', &tmpNext);
			if (i != 0)
			{
				if (pub_set_next_token(cHeader->addr, tmp, '\n', &tmpNext) < 0)
					return -1;
			}
		}
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//  	printf("c: %d, %d, %s\n", sdp->c.netType, sdp->c.addrType, sdp->c.addr);

	if (sdp->medias.num == 0)
		sdp->flag |= PUB_SDP_FLAG_C;
	else
		sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_C;

	return 0;
}

int pub_sdp_parse_m_c_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char				*equal;
	char				*crlf;
	char				*tmp;
	char				*tmpNext;
	char				value[16];
	char				*slash;
	PUB_SDP_C		*cHeader;
	int				i;

	*next = buf;
	equal = buf;

	if (sdp->medias.num == 0)
		return -1;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "c"
	if (equal[-1] != 'c')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // c=\r ?? bad header

	if ((flag & PUB_SDP_FLAG_C) == PUB_SDP_FLAG_C)
	{
		tmp = equal + 1;

		// c=nettype addrtype (multicastaddr | addr)

	  	// nettype is "IN" and will be extended
		if (pub_set_next_token (value, tmp, ' ', &tmpNext) < 0)
			return -1;

		if (pub_sdp_net_type_conv(value, &sdp->medias.medias[sdp->medias.num - 1].c.netType, PUB_SDP_STR_TO_API) < 0)
			return -1;

		tmp = tmpNext;

		// nettype is "IP4" or "IP6" and will be extended
		if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
			return -1;

		if (pub_sdp_addr_type_conv(value, &sdp->medias.medias[sdp->medias.num - 1].c.addrType, PUB_SDP_STR_TO_API) < 0)
			return -1;

		tmp = tmpNext;

		/* there we have a multicast or unicast address */
		/* multicast can be ip/ttl [/integer] */
		/* unicast is FQDN or ip (no ttl, no integer) */

		slash = strchr (tmp, '/');
		cHeader = &sdp->medias.medias[sdp->medias.num - 1].c;

		if (slash != NULL && slash < crlf)  // it's a multicast address!
		{
			// Not supported for the moment
		}
		else
		{
			// in this case, we have a unicast address
			i = pub_set_next_token(cHeader->addr, tmp, '\r', &tmpNext);
			if (i != 0)
			{
				if (pub_set_next_token(cHeader->addr, tmp, '\n', &tmpNext) < 0)
					return -1;
			}
		}
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//  	printf("c: %d, %d, %s\n", sdp->c.netType, sdp->c.addrType, sdp->c.addr);

	sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_C;

	return 0;
}

int pub_sdp_parse_b_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "b"
	if (equal[-1] != 'b')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

	return 0;
}

int pub_sdp_parse_t_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char				*equal;
	char				*crlf;
	char				*tmp;
	char				*tmpNext;
	char				value[16];
	int				i;
	PUB_SDP_T		*tHeader;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "t"
	if (equal[-1] != 't')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           /* t=\r ?? bad header */

	if ((flag & PUB_SDP_FLAG_T) == PUB_SDP_FLAG_T)
	{
		tmp = equal + 1;
		// t = start_time stop_time
		tHeader = &sdp->t;

		if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)	
			return -1;

		tHeader->startTime = atoi(value);  
		tmp = tmpNext;

		i = pub_set_next_token(value, tmp, '\r', &tmpNext);

		if (i != 0)
		{
			if (pub_set_next_token(value, tmp, '\n', &tmpNext) < 0)
				return -1;

			tHeader->stopTime = atoi(value);
		}
		else
		{
			tHeader->stopTime = atoi(value);
		}
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//  	printf("t: %ld, %ld\n", sdp->t.startTime, sdp->t.stopTime);

	sdp->flag |= PUB_SDP_FLAG_T;

	return 0;
}

int pub_sdp_parse_r_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "r"
	if (equal[-1] != 'r')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

	return 0;
}

int pub_sdp_parse_z_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "z"
	if (equal[-1] != 'z')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

	return 0;
}

int pub_sdp_parse_k_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char		*equal;
	char		*crlf;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "k"
	if (equal[-1] != 'k')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           // v=\r ?? bad header

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

	return 0;
}

int pub_sdp_parse_a_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char				*equal;
	char				*crlf;
	char				*tmp;
	char				*tmpNext;
	char				value[32];
	int				i, ret;
	PUB_SDP_A		*a;
	char				*colon;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "a"
	if (equal[-1] != 'a')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           /* a=\r ?? bad header */

	if ((flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
	{
		tmp = equal + 1;
		a = &sdp->a;
		// a=att-field[:att-value]

		// is there any att-value?
		colon = strchr (equal + 1, ':');

		if ((colon != NULL) && (colon < crlf))
		{
			// att-field is alpha-numeric
			if (pub_set_next_token(value, tmp, ':', &tmpNext) < 0)
				return -1;

			if ((ret = pub_sdp_attr_type_conv(value, &a->aType, PUB_SDP_STR_TO_API)) == -1)
				return -1;
			else if (ret == -2)
			{
				if (crlf[1] == '\n')
					*next = crlf + 2;
				else
					*next = crlf + 1;

				return 0;
			}

			tmp = tmpNext;

			i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);

			if (i != 0)
			{
				if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
					return -1;
			}
		}
		else
		{
			i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);

			if (i != 0)
			{
				if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
					return -1;
			}
		}

		sdp->medias.medias[sdp->medias.num - 1].attrs.num++;
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//  	printf("a: %d, %s\n", a->aType, a->aValue);

	sdp->flag |= PUB_SDP_FLAG_A;

	return 0;
}

int pub_sdp_parse_m_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char				*equal;
	char				*crlf;
	char				*tmp;
	char				*tmpNext;
	char				value[32];
	int				i;
	PUB_SDP_M		*mHeader;
	BYTE			num;
	char				*slash;
	char				*space;
	int				moreSpace;
	int				ret;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "m"
	if (equal[-1] != 'm')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           /* a=\r ?? bad header */

	if ((flag & PUB_SDP_FLAG_M) == PUB_SDP_FLAG_M)
	{
		tmp = equal + 1;
		num = sdp->medias.num;
		mHeader = &sdp->medias.medias[num].m;
		// m=media port ["/"integer] proto *(payload_number)
		// media is "audio" "video" "application" "data" or other...
		if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
			return -1;
		if ((ret = pub_sdp_media_type_conv(value, &mHeader->media, PUB_SDP_STR_TO_API)) < 0)
		{
			if (-2 == ret)
			{	
				if (crlf[1] == '\n')
					*next = crlf + 2;
				else
					*next = crlf + 1;

				return 0;
			}

			return -1;
		}
		tmp = tmpNext;

		slash = strchr (tmp, '/');
		space = strchr (tmp, ' ');

		if ((slash != NULL) && (slash < space))
		{	/* a number of port is specified! */
			if (pub_set_next_token(value, tmp, '/', &tmpNext) < 0)
				return -1;

			if (strcmp(value, "$") == 0)
			{
				mHeader->port = PUB_SDP_M_PORT_CHOOSE;
			}
			else
			{
				mHeader->port = atoi(value);
			}

			tmp = tmpNext;

			if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
				return -1;

			mHeader->portNum = atoi(value);

			tmp = tmpNext;
		}
		else
		{
			if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
				return -1;

			if (strcmp(value, "$") == 0)
			{
				mHeader->port = PUB_SDP_M_PORT_CHOOSE;
			}
			else
			{
				mHeader->port = atoi(value);
			}

			tmp = tmpNext;
		}

		if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
			return -1;

		if ((ret = pub_sdp_proto_type_conv(value, &mHeader->proto, PUB_SDP_STR_TO_API)) < 0)
		{
			if (ret == -2)
			{
				if (crlf[1] == '\n')
					*next = crlf + 2;
				else
					*next = crlf + 1;

				sdp->medias.medias[sdp->medias.num].flag |= PUB_SDP_FLAG_M;
				sdp->flag |= PUB_SDP_FLAG_M;
				sdp->medias.num++;

				return 0;
			}

			return -1;
		}

		tmp = tmpNext;

		space = strchr(tmp + 1, ' ');

		if (space == NULL)
			moreSpace = 1;
		else if ((space != NULL) && (space > crlf))
			moreSpace = 1;
		else
			moreSpace = 0;

		while(moreSpace == 0)
		{
			if (pub_set_next_token(value, tmp, ' ', &tmpNext) < 0)
				return -1;

			mHeader->payloads[mHeader->plNum++] = atoi(value);
			tmp = tmpNext;

			space = strchr(tmp + 1, ' ');

			if (space == NULL)
				moreSpace = 1;
			else if ((space != NULL) && (space > crlf))
				moreSpace = 1;
			else
				moreSpace = 0;
		}

		if (tmpNext < crlf)
		{                         // tmpNext is still less than clrf: no space
			i = pub_set_next_token(value, tmp, '\r', &tmpNext);

			if (i != 0)
			{
				if (pub_set_next_token(value, tmp, '\n', &tmpNext) < 0)
					return -1;
			}
			mHeader->payloads[mHeader->plNum++] = atoi(value);
		}
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//    printf("m: %d, %d, %d, %d, %d, %d, %d\n", mHeader->media, mHeader->port, mHeader->portNum, mHeader->proto, mHeader->plNum, mHeader->payloads[0], mHeader->payloads[1]);

	sdp->medias.medias[sdp->medias.num].flag |= PUB_SDP_FLAG_M;
	sdp->flag |= PUB_SDP_FLAG_M;
	sdp->medias.num++;

	return 0;}

int pub_sdp_parse_m_a_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **next, DWORD flag)
{
	char				*equal;
	char				*crlf;
	char				*tmp;
	char				*tmpNext;
	char				value[32];
	int				i, ret;
	BYTE			num, mediaNum;
	PUB_SDP_A		*a;
	char				*colon;

	*next = buf;
	equal = buf;

	while ((*equal != '=') && (*equal != '\0'))
		equal++;

	if (*equal == '\0')
		return -1;

	// check if header is "a"
	if (equal[-1] != 'a')
		return -2;

	crlf = equal + 1;

	while ((*crlf != '\r') && (*crlf != '\n') && (*crlf != '\0'))
		crlf++;

	if (*crlf == '\0')
		return -1;

	if (crlf == equal + 1)
		return -1;           /* a=\r ?? bad header */

	if ((flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
	{
		tmp = equal + 1;
		mediaNum = sdp->medias.num;
		num = sdp->medias.medias[mediaNum - 1].attrs.num;
		a = &sdp->medias.medias[mediaNum - 1].attrs.attrs[num];

		// a=att-field[:att-value]

	  	// is there any att-value?
		colon = strchr (equal + 1, ':');

		if ((colon != NULL) && (colon < crlf))
		{
			// att-field is alpha-numeric
			if (pub_set_next_token(value, tmp, ':', &tmpNext) < 0)
				return -1;

			if ((ret = pub_sdp_attr_type_conv(value, &a->aType, PUB_SDP_STR_TO_API)) == -1)
				return -1;
			else if (ret == -2)
			{
				if (crlf[1] == '\n')
					*next = crlf + 2;
				else
					*next = crlf + 1;

				return 0;
			}

			tmp = tmpNext;

			i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);

			if (i != 0)
			{
				if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
					return -1;
			}
		}
		else
		{
			i = pub_set_next_token(a->aValue, tmp, '\r', &tmpNext);

			if (i != 0)
			{
				if (pub_set_next_token(a->aValue, tmp, '\n', &tmpNext) < 0)
					return -1;
			}
		}

		sdp->medias.medias[sdp->medias.num - 1].attrs.num++;
	}

	if (crlf[1] == '\n')
		*next = crlf + 2;
	else
		*next = crlf + 1;

//  	printf("a: %d, %s\n", a->aType, a->aValue);

	if (sdp->medias.num == 0)
		sdp->flag |= PUB_SDP_FLAG_A;
	else
		sdp->medias.medias[sdp->medias.num - 1].flag |= PUB_SDP_FLAG_A;

	return 0;
}

int pub_sdp_check_ending_for_megaco(char *ptr, char **nextbuf)
{
	*nextbuf = ptr;
	
	if ((*ptr == '\0') || (*ptr == '\r') || (*ptr == '\n'))
	{	
		return 0;
	}
	else if (((ptr[0] == '.') && (ptr[1] == '\r') && (ptr[2] == '\n')))
	{
		*nextbuf = ptr + 3;
		return 1;   
	}
	else
		return -1;   
}

int pub_sdp_parse_for_megaco(PUB_SDP_MSG *sdp, char *buf, char **nextMsg, DWORD flag)
{
  	// In SDP, headers must be in the right order
  	/* This is a simple example
	     v=0
	     o=user1 53655765 2353687637 IN IP4 128.3.4.5
	     s=Mbone Audio
	     i=Discussion of Mbone Engineering Issues
	     e=mbone@somewhere.com
	     c=IN IP4 224.2.0.1/127
	     t=0 0
	     m=audio 3456 RTP/AVP 0
	     a=rtpmap:0 PCMU/8000
   	*/

	char 	*nextBuf;
	char 	*ptr;
	int 	i;
	int     ret;
	int 	moreHeader = 1;

	pub_sdp_msg_init(sdp);

  	ptr = (char *)buf;
  
	// mandatory
	if (pub_sdp_parse_v_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;
	ptr = nextBuf;

	// mandatory
	if (pub_sdp_parse_o_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;
	ptr = nextBuf;

	// mandatory
	if (pub_sdp_parse_s_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;
	ptr = nextBuf;

	// optional
	if (pub_sdp_parse_i_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;
	ptr = nextBuf;

	// optional
	if (pub_sdp_parse_u_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;
	ptr = nextBuf;

	// optional
	i = 0;
	while (i == 0)
	{
		if ((i = pub_sdp_parse_e_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
			return -1;
		ptr = nextBuf;
	}

	// optional
	i = 0;
	while (i == 0)
	{
		if ((i = pub_sdp_parse_p_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
			return -1;
		ptr = nextBuf;
	}

	// optional
	if (pub_sdp_parse_c_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;
	ptr = nextBuf;

	// optional
	i = 0;
	while (i == 0)
	{
		if ((i = pub_sdp_parse_b_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
			return -1;
		ptr = nextBuf;
	}
	
	// mandatory
	if (pub_sdp_parse_t_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;
  
	if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
	{
		*nextMsg = nextBuf;
		return ret;
	}

	ptr = nextBuf;

	// optional
	i = 0;
	while (i == 0)
	{
		if ((i = pub_sdp_parse_r_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
			return -1;
      	
		if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
		{
			*nextMsg = nextBuf;
			return ret;
		}
		ptr = nextBuf;
	}

	// optional
	if (pub_sdp_parse_t_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;

	if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
	{
		*nextMsg = nextBuf;
		return ret;
	}
	ptr = nextBuf;

	while (moreHeader == 1)
	{
		i = 0;
		while (i == 0)          // is a "r" header
		{
			if ((i = pub_sdp_parse_r_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
				return -1;

			if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
			{
				*nextMsg = nextBuf;
				return ret;
			}
			ptr = nextBuf;
		}

		if ((i = pub_sdp_parse_t_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
			return -1;
		else if (i == -2)
			moreHeader = 0;	// no more "t" headers
		else
			moreHeader = 1;

		if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
		{
			*nextMsg = nextBuf;
			return ret;
		}
		ptr = nextBuf;
	}

	// optional
	if (pub_sdp_parse_z_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;

	if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
	{
		*nextMsg = nextBuf;
		return ret;
	}
	ptr = nextBuf;

	// optional
	if (pub_sdp_parse_k_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
		return -1;

	if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
	{
		*nextMsg = nextBuf;
		return ret;
	}
	ptr = nextBuf;

	// optional
	// 0 or more "a" header
	i = 0;
	while (i == 0)                // no more "a" header
	{
		if ((i = pub_sdp_parse_a_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
			return -1;

		if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
		{
			*nextMsg = nextBuf;
			return ret;
		}
		ptr = nextBuf;
	}

	moreHeader = 0;
	while (moreHeader == 0)
	{
		// optional
		if ((moreHeader = pub_sdp_parse_m_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
			return -1;
		else if (moreHeader == -2)
			break;

		if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
		{
			*nextMsg = nextBuf;
			return ret;
		}
		ptr = nextBuf;

		// optional
		if (pub_sdp_parse_i_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
			return -1;

		if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
		{
			*nextMsg = nextBuf;
			return ret;
		}
		ptr = nextBuf;

		// optional
		i = 0;

		while (i == 0)
		{
			if ((i = pub_sdp_parse_m_c_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
				return -1;

			if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
			{
				*nextMsg = nextBuf;
				return ret;
			}
			ptr = nextBuf;
		}

		// optional
		i = 0;

		while (i == 0)
		{
			if ((i = pub_sdp_parse_b_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
				return -1;

			if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
			{
				*nextMsg = nextBuf;
				return ret;
			}
			ptr = nextBuf;
		}

		// optional
		if (pub_sdp_parse_k_for_megaco(sdp, ptr, &nextBuf, flag) == -1)
			return -1;

		if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
		{
			*nextMsg = nextBuf;
			return ret;
		}
		ptr = nextBuf;

		// optional
		i = 0;

		while (i == 0)
		{
			if ((i = pub_sdp_parse_m_a_for_megaco(sdp, ptr, &nextBuf, flag)) == -1)
				return -1;
			if ((ret = pub_sdp_check_ending_for_megaco(nextBuf, &nextBuf)) >= 0)
			{
				*nextMsg = nextBuf;
				return ret;
			}
			ptr = nextBuf;
		}
	}

	return 0;
}

// SDP Encode

int pub_sdp_encode_v(PUB_SDP_V *v, char *dest)
{
	sprintf(dest, "v=%d\r\n", v->value);
	
	return 0;
}

int pub_sdp_encode_o(PUB_SDP_O *o, char *dest)
{
	char 	origin[128];
	char	netType[8];
	char	addrType[8];
	
	if (pub_sdp_net_type_conv(netType, &o->netType, PUB_SDP_API_TO_STR) < 0)
		return -1;
	
	if (pub_sdp_addr_type_conv(addrType, &o->addrType, PUB_SDP_API_TO_STR) < 0)
		return -1;
	
	sprintf(origin, "o=%s %s %s %s %s %s\r\n", o->userName, o->sessId, o->sessVer, netType, addrType, o->addr);
	
	strcat(dest, origin);
	
	return 0;
}

int pub_sdp_encode_s(PUB_SDP_S *s, char *dest)
{
	char 	sess[64];
	
	sprintf(sess, "s=%s\r\n", s->sessName);
	
	strcat(dest, sess);
	
	return 0;
}

int pub_sdp_encode_i(PUB_SDP_I *i, char *dest)
{
	char 	info[64];
	
	sprintf(info, "i=%s\r\n", i->info);
	
	strcat(dest, info);
	
	return 0;
}

int pub_sdp_encode_c(PUB_SDP_C *c, char *dest)
{
	char 	conn[128];
	char	netType[8];
	char	addrType[8];
	
	if (pub_sdp_net_type_conv(netType, &c->netType, PUB_SDP_API_TO_STR) < 0)
		return -1;
	
	if (pub_sdp_addr_type_conv(addrType, &c->addrType, PUB_SDP_API_TO_STR) < 0)
		return -1;
	
	sprintf(conn, "c=%s %s %s\r\n", netType, addrType, c->addr);
	
	strcat(dest, conn);
	
	return 0;
}

int pub_sdp_encode_t(PUB_SDP_T *t, char *dest)
{
	char 	time[64];
	
	sprintf(time, "t=%u %u\r\n", t->startTime, t->stopTime);
	
	strcat(dest, time);
	
	return 0;
}

int pub_sdp_encode_m(PUB_SDP_M *m, char *dest, WORD flag)
{
	char 	media[128];
	char	mediaType[8] = "";
	char	proto[32];
	char	payload[64];
	BYTE	i;
	
	if (pub_sdp_media_type_conv(mediaType, &m->media, PUB_SDP_API_TO_STR) < 0)
		return -1;
	
	if (pub_sdp_proto_type_conv(proto, &m->proto, PUB_SDP_API_TO_STR) < 0)
		return -1;
	
	sprintf(media, "m=%s %d %s", mediaType, m->port, proto);

	if (m->proto == PUB_SDP_PROTO_TYPE_RTP_AVP)
	{
	    if ((flag & PUB_MGCP_PARA_FLAG_TFO) == PUB_MGCP_PARA_FLAG_TFO)
	    {
               sprintf(payload, " %d", 8);
               strcat(media, payload);
           }
	
           for (i = 0; i < m->plNum; i++)
           {
               if (i >= PUB_SDP_MAX_PAYLOAD_NUM)
                   break;

		sprintf(payload, " %d", m->payloads[i]);
		strcat(media, payload);
           }
	}
	strcat(media, "\r\n");
	
	strcat(dest, media);
	
	return 0;
}

int pub_sdp_encode_a(PUB_SDP_A *a, char *dest)
{
	char 	attr[128];
	char	attrType[32];
	int     ret;
	
	if ((ret = pub_sdp_attr_type_conv(attrType, &a->aType, PUB_SDP_API_TO_STR)) == -1)
		return -1;

    if (ret == -2)
    {
        sprintf(attr, "a=%s\r\n", a->aValue);
    }
    else
    {
	    sprintf(attr, "a=%s:%s\r\n", attrType, a->aValue);
	}
	
	strcat(dest, attr);
	
	return 0;
}

int pub_sdp_encode(PUB_SDP_MSG *sdp, char *dest, WORD flag)
{
	BYTE			i, j;
	BYTE			mediaNum, attrNum;
	PUB_SDP_MEDIA	*media;
	PUB_SDP_A		*a;
	
	if ((sdp->flag & PUB_SDP_FLAG_V) == PUB_SDP_FLAG_V)
	{
		if (pub_sdp_encode_v(&sdp->v, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_O) == PUB_SDP_FLAG_O)
	{
		if (pub_sdp_encode_o(&sdp->o, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_S) == PUB_SDP_FLAG_S)
	{
		if (pub_sdp_encode_s(&sdp->s, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_I) == PUB_SDP_FLAG_I)
	{
		if (pub_sdp_encode_i(&sdp->i, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_C) == PUB_SDP_FLAG_C)
	{
		if (pub_sdp_encode_c(&sdp->c, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_T) == PUB_SDP_FLAG_T)
	{
		if (pub_sdp_encode_t(&sdp->t, dest) < 0)
			return -1;
	}

	if ((sdp->flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
	{
		if (pub_sdp_encode_a(&sdp->a, dest) < 0)
			return -1;
	}

	if ((sdp->flag & PUB_SDP_FLAG_M) == PUB_SDP_FLAG_M)
	{
		mediaNum = sdp->medias.num;
		for (i = 0; i < mediaNum; i++)
		{
			media = &sdp->medias.medias[i];
			if (pub_sdp_encode_m(&media->m, dest, flag) < 0)
				return -1;
			
			if ((media->flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
			{
				attrNum = media->attrs.num;
				for (j = 0; j < attrNum; j++)
				{
					a = &media->attrs.attrs[j];
					if (pub_sdp_encode_a(a, dest) < 0)
						return -1;
				}
			}
		}
	}
	
	return 0;
}

//SDP encode for megaco

int pub_sdp_encode_v_for_megaco(PUB_SDP_V *v, char *dest)
{
	sprintf(dest, "v=%d\r\n", v->value);

	return 0;
}

int pub_sdp_encode_o_for_megaco(PUB_SDP_O *o, char *dest)
{
	char			origin[128];
	char			netType[8];
	char			addrType[8];

	if (pub_sdp_net_type_conv(netType, &o->netType, PUB_SDP_API_TO_STR) < 0)
		return -1;

	if (pub_sdp_addr_type_conv(addrType, &o->addrType, PUB_SDP_API_TO_STR) < 0)
		return -1;

	sprintf(origin, "o=%s %s %s %s %s %s\r\n", o->userName, o->sessId, o->sessVer, netType, addrType, o->addr);

	strcat(dest, origin);

	return 0;
}

int pub_sdp_encode_s_for_megaco(PUB_SDP_S *s, char *dest)
{
	char		sess[64];

	sprintf(sess, "s=%s\r\n", s->sessName);

	strcat(dest, sess);

	return 0;
}

int pub_sdp_encode_i_for_megaco(PUB_SDP_I *i, char *dest)
{
	char		info[64];

	sprintf(info, "i=%s\r\n", i->info);

	strcat(dest, info);

	return 0;
}

int pub_sdp_encode_c_for_megaco(PUB_SDP_C *c, char *dest)
{
	char		conn[128];
	char		netType[8];
	char		addrType[8];

	if (pub_sdp_net_type_conv(netType, &c->netType, PUB_SDP_API_TO_STR) < 0)
		return -1;

	if (pub_sdp_addr_type_conv(addrType, &c->addrType, PUB_SDP_API_TO_STR) < 0)
		return -1;

	sprintf(conn, "c=%s %s %s\r\n", netType, addrType, c->addr);

	strcat(dest, conn);

	return 0;
}

int pub_sdp_encode_t_for_megaco(PUB_SDP_T *t, char *dest)
{
	char		time[64];

	sprintf(time, "t=%u %u\r\n", t->startTime, t->stopTime);

	strcat(dest, time);

	return 0;
}

int pub_sdp_encode_m_for_megaco(PUB_SDP_M *m, char *dest, WORD flag)
{
	char			media[128];
	char			mediaType[8] = "";
	char			proto[32];
	char			payload[64];
	BYTE		i;
	char			port[8] = "";

	if (pub_sdp_media_type_conv(mediaType, &m->media, PUB_SDP_API_TO_STR) < 0)
		return -1;

	if (pub_sdp_proto_type_conv(proto, &m->proto, PUB_SDP_API_TO_STR) < 0)
		return -1;

	if (m->port == PUB_SDP_M_PORT_CHOOSE)
	{
		strcpy(port, "$");
	}
	else
	{
		sprintf(port, "%d", m->port);
	}

	sprintf(media, "m=%s %s %s", mediaType, port, proto);

	if (m->proto == PUB_SDP_PROTO_TYPE_RTP_AVP)
	{
		if ((flag & PUB_MGCP_PARA_FLAG_TFO) == PUB_MGCP_PARA_FLAG_TFO)
		{
			sprintf(payload, " %d", 8);
			strcat(media, payload);
		}

		for (i = 0; i < m->plNum; i++)
		{
			if (i >= PUB_SDP_MAX_PAYLOAD_NUM)
				break;

			sprintf(payload, " %d", m->payloads[i]);
			strcat(media, payload);
		}
	}

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

	strcat(dest, media);

	return 0;
}

int pub_sdp_encode_a_for_megaco(PUB_SDP_A *a, char *dest)
{
	char		attr[128];
	char		attrType[32];
	int		ret;

	if ((ret = pub_sdp_attr_type_conv(attrType, &a->aType, PUB_SDP_API_TO_STR)) == -1)
		return -1;

	if (ret == -2)
	{
		sprintf(attr, "a=%s\r\n", a->aValue);
	}
	else
	{
		sprintf(attr, "a=%s:%s\r\n", attrType, a->aValue);
	}

	strcat(dest, attr);

	return 0;
}


int pub_sdp_encode_for_megaco(PUB_SDP_MSG *sdp, char *dest, WORD flag)
{
	BYTE			i, j;
	BYTE			mediaNum, attrNum;
	PUB_SDP_MEDIA	*media;
	PUB_SDP_A		*a;
	
	if ((sdp->flag & PUB_SDP_FLAG_V) == PUB_SDP_FLAG_V)
	{
		if (pub_sdp_encode_v_for_megaco(&sdp->v, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_O) == PUB_SDP_FLAG_O)
	{
		if (pub_sdp_encode_o_for_megaco(&sdp->o, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_S) == PUB_SDP_FLAG_S)
	{
		if (pub_sdp_encode_s_for_megaco(&sdp->s, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_I) == PUB_SDP_FLAG_I)
	{
		if (pub_sdp_encode_i_for_megaco(&sdp->i, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_C) == PUB_SDP_FLAG_C)
	{
		if (pub_sdp_encode_c_for_megaco(&sdp->c, dest) < 0)
			return -1;
	}
	
	if ((sdp->flag & PUB_SDP_FLAG_T) == PUB_SDP_FLAG_T)
	{
		if (pub_sdp_encode_t_for_megaco(&sdp->t, dest) < 0)
			return -1;
	}

	if ((sdp->flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
	{
		if (pub_sdp_encode_a_for_megaco(&sdp->a, dest) < 0)
			return -1;
	}

	if ((sdp->flag & PUB_SDP_FLAG_M) == PUB_SDP_FLAG_M)
	{
		mediaNum = sdp->medias.num;
		for (i = 0; i < mediaNum; i++)
		{
			media = &sdp->medias.medias[i];
			if (pub_sdp_encode_m_for_megaco(&media->m, dest, flag) < 0)
				return -1;
			
			if ((media->flag & PUB_SDP_FLAG_A) == PUB_SDP_FLAG_A)
			{
				attrNum = media->attrs.num;
				for (j = 0; j < attrNum; j++)
				{
					a = &media->attrs.attrs[j];
					if (pub_sdp_encode_a_for_megaco(a, dest) < 0)
						return -1;
				}
			}
		}
	}
	
	return 0;
}

/*@end@*/
