/*
 *
 *
 *    inaddr.cc
 *
 *    C++ source code for class my::inaddr.
 *
 *    =========================================================================
 *
 *    Copyright (C) 1999-2013 by Matt Roberts, KK5JY.
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation; either
 *    version 2.1 of the License, or (at your option) any later version.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *    =========================================================================
 *
 *
 */


#include <my++/inaddr.h>
#include <cstdlib>

using namespace std;


/*
 *
 *   my::inet_address::to_string (std::string &)
 *
 */

std::string & my::inet_address::to_string (std::string &s) const {
	char buffer [DOTTED_QUAD_LENGTH_MAX];
	uint32_t i = ntohl (address.s_addr);

	unsigned b0 = (i & 0x000000FF);
	unsigned b1 = (i & 0x0000FF00) >> 8;
	unsigned b2 = (i & 0x00FF0000) >> 16;
	unsigned b3 = (i & 0xFF000000) >> 24;

	snprintf (buffer, sizeof(buffer), "%u.%u.%u.%u", b3, b2, b1, b0);
	s = buffer;
	return s;
}


/*
 *
 *   iostream operations
 *
 */

namespace my {
	ostream &operator << (ostream &o, const my::inet_address &a) {
		std::string s;
		a.to_string(s);
		o << s;
		return o;
	}
	
	istream &operator >> (istream &i, my::inet_address &a) {
		std::string s;
		i >> s;
		a.readAddressFromString (s);
		return i;
	}
}


/*
 *
 *    my::inet_address::readHostnameFromString (const std::string &)
 *
 */

bool my::inet_address::readHostnameFromString (const std::string &s) {
	std::string t;
	my::host_entry he(s);

	if (!he) {
		clear ();
		return false;
	}

	he.getAddress (0, address);
	return true;
}


/*
 *
 *    my::inet_address::readAddressFromString (const std::string &)
 *
 */

bool my::inet_address::readAddressFromString (const std::string &s) {
	std::string t = "";
	std::string::const_iterator si;
	int i;

	for (si = s.begin(), i = 0;
			si != s.end();
			si++) {
		if (! ((isdigit(*si) || (*si == '.'))  // not portable to ipv6 -- FIXME
					&& (i < (DOTTED_QUAD_LENGTH_MAX - 1))))
			break;
	}

	t.append (s.begin(), si);

	if (!inet_aton (t.c_str(), &address)) {
		clear ();
		return false;
	} else {
		return true;
	}
}


/*
 *
 *    my::inet_address::readNetmaskFromString (const std::string &)
 *
 */

bool my::inet_address::readNetmaskFromString (const std::string &s) {
	std::string t = "";
	std::string::const_iterator si;
	size_t ti;
	int i = 0;
	bool slashed = false;

	for (si = s.begin(); si != s.end(); ++si) {
		if ((*si) == '/') {
			slashed = true;            /* remember that we found a slash */
			t.assign(si + 1, s.end()); /* copy [si+1, s.end) -> t */
			break;
		}
	}

	// if no network mask given, assume host mask and return
	if (!t.length()) {
		address.s_addr = htonl (0xFFFFFFFF);
		return true;
	}

	ti = t.find (".");

	if (ti != std::string::npos) {
		if (inet_aton (t.c_str(), &address) == 0) {
			clear ();
			return false;
		} else {
			return true;
		}
	} else {
		// if no network mask given, assume host mask and return
		if (slashed) {
			i = atoi (t.c_str());
			if (i == 0) {
				address.s_addr = htonl(0x00000000);
			} else if (i == 32) {
				address.s_addr = htonl(0xFFFFFFFF);
			} else if ((i < 0) || (i > 32)) {
				address.s_addr = htonl(0xFFFFFFFF);
			} else {
				address.s_addr = htonl((0xFFFFFFFF << (32 - i)) & 0xFFFFFFFF);
			}
		} else {
			address.s_addr = htonl(0xFFFFFFFF);
		}
	}

	return true;
}
