/*
 * Sdp mangler module
 *
 * Copyright (C) 2001-2003 FhG Fokus
 *
 * This file is part of opensips, a free SIP server.
 *
 * opensips is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * opensips is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * History:
 * --------
 *  2003-04-07 first version.
 */

#include "ip_helper.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <netinet/in.h>

/* given an ip and a mask it provides network address */
unsigned int
net_address (unsigned int ip, unsigned int mask)
{
	return (ip & mask);
}

/*
	returns 1 if ip belongs to address/net or 0 if not
*/
int
same_net (unsigned int ip, unsigned int address, unsigned int mask)
{
	return ((address & mask) == (ip & mask));
}


/* Small help func takes ip-address-integer and returns string
   representation */
void
ip2str (unsigned int address, char **rr)
{
	int i;
	char *hlp, hlp2[5];	/* initial era hlp2[18] */
	unsigned char *addrp = (unsigned char *) &address;
	hlp = (char *) malloc (18);
	hlp[0] = '\0';

	for (i = 0; i < 3; i++)
	{
		sprintf (hlp2, "%i.", addrp[i]);
		hlp = strcat (hlp, (char *) hlp2);
	}
	sprintf (hlp2, "%i", addrp[3]);
	hlp = strcat (hlp, hlp2);
	*rr = hlp;
}

/* Small help func takes ip-address-string, determines its validity
   and write the integer representation at address.
   Returns 1 if successful converted, 0 if the dotted isn't valid.
   If you want to parse IP/netmask pairs, call parse_ip_netmask
   first - it will remove the netmask, then use this func */
int
parse_ip_address (char *c, unsigned int *address)	//inet_aton
{
	int quat, i, j, digit_bol;
	char buf[20];
	char *p, *q, *r;
	unsigned char *addrp;

	if (c == NULL)
		return 0;
	if (strlen (c) >= 16)
		return 0;

	quat = 0;
	digit_bol = 1;
	buf[0] = '\0';
	/* cool dirty hack to address the bytes of the int easily */
	addrp = (unsigned char *) address;

	/* make a copy of the dotted string, because we modify it */
	strncpy (buf, c, 19);
	p = buf;

	/* search three times for a dot in the string */
	for (i = 0; i < 3; i++)
	{
		if ((q = strchr (p, '.')) == NULL)
			return 0;
		else
		{
			*q = '\0';	/* cut off at the dot */
			if (strlen (p))	/* is the distance between dots greater 0 */
			{
				r = p;
				for (j = 0; j < strlen (p); j++, r++)	/* are all char of the
									 * byte digits */
					digit_bol = digit_bol && isdigit ((unsigned char)*r);
				if (digit_bol)
				{
					quat = atoi (p);
					if (quat > 255)	/* is it a byte or greater */
						return 0;
					else
						addrp[i] =
							(unsigned char) quat;
				}
				else
					return 0;
			}
			else
				return 0;
		}
		p = q + 1;
	}			/* for */

	/* and the last byte */
	if (strlen (p))
	{
		r = p;
		for (j = 0; j < strlen (p); j++, r++)
			digit_bol = digit_bol && isdigit ((unsigned char)*r);
		if (digit_bol)
		{
			quat = atoi (p);
			if (quat > 255)
				{
				return 0;
				}
			else
				addrp[3] = (unsigned char) quat;
			return 1;
		}
		else
			{
			return 0;
			}
	}
	else
		{
		return 0;
		}
}

/* return 1 if ALL str is a positive number or 0. no + signs allowed*/
int
is_positive_number (char *str)
{
	int i;
	if (str == NULL)
		return 0;
	for (i = 0; i < strlen (str); i++)
	{
		if (isdigit ((unsigned char)str[i]) == 0)
			return 0;
	}
	return 1;
}

/* return 0 in case of error */
unsigned int
make_mask (unsigned int length)
{
	unsigned int res;
	if ((length < 8) || (length > 30))
		return -1;	/* invalid value for mask */
	/* fill it with 1 */
	res = 0xFFFFFFFF;
	/* shift it to right with 32-length positions */
	res = htonl (res << (32 - length));
	return res;
}

/* Small help func takes ip-address-string, determines if a valid
   netmask is specified and inserts the netmask into mask.
   Cuts of the netmask of the string, if it founds a netmask !!!
   Returns 0 if no netmask found, -1 if netmask isn't valid, and
   1 if successful.
	According to this function a mask is in form of 255.255.192.0
	so an ip/mask looks like 10.0.0.0/255.255.192.0
	we will extend it to 10.0.0.0/18 which will be also valid
*/
int
parse_ip_netmask (char *c, char **ip, unsigned int *mask)
{
	char *p, *q;
	unsigned int netmask;

	if (c == NULL)
	{
		return -10;
	}
	p = c;


	if ((q = strchr (p, '/')) == NULL)
	{
		*mask = 0xFFFFFFFF;
		return 0;	/* no mask */
	}
	else
	{
		*ip = (char *) malloc (q - p + 1);
		if ((*ip) == NULL)
			return -2;
		memcpy (*ip, p, q - p);
		(*ip)[q - p] = 0;

		// wrong (*q) = 0;                            /* cut of the netmask */
		q++;
		/*
		 * two possibilities /16 or /255.255.192.0
		 */
		if (is_positive_number (q) == 1)
		{
			/* we have a /16 mask */
			if ((netmask = make_mask (atoi (q))) == 0)
			{
				*mask = 0;	/* error in value of /43 or something like */
				return -1;
			}
			else
			{
				*mask = netmask;
				return 1;
			}
		}
		else /* we may have a 255.255.192.0 mask */ if (parse_ip_address (q, &netmask) == 1)	/* and parse the netmask */
		{
			*mask = netmask;
			return 1;
		}
		else
		{
			*mask = 0;
			return -1;
		}
	}
}

