/*
 * addr2uncompaddr: Support a function to format a given address to an
 *                   uncompressed one
 *                   (anti RFC 1884)
 *
 * Version:		$Id: addr2uncompaddr.c,v 0.10 2001/03/03 $
 * 
 * Author:		Peter Bieringer <pb@bieringer.de>
 *
 * based on code from "ircd", hint by Arkadiusz Mikiewicz <misiek@pld.org.pl>
 * some hints taken from ifconfig.c (net-tools)
 * 
 * Credits to:
 *	Arkadiusz Miskiewicz <misiek@pld.ORG.PL>
 *	 for his hints
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h> 
#include "ipv6calc.h"

void printhelp_addr2uncompaddr() {
	fprintf(stderr, " %s --addr2uncompaddr ipv6addr[/prefixlength]\n", PROGRAM_NAME);
};

void printhelplong_addr2uncompaddr() {
	printhelp_addr2uncompaddr();
	fprintf(stderr, "  Converts given IPv6 address to an uncompressed one\n");
	fprintf(stderr, "   e.g. 3ffe:400:100:f101::1 -> 3ffe:400:100:f101:0:0:0:1\n");
	fprintf(stderr, "   e.g. 3ffe:400:100:f101::1/64 -> 3ffe:400:100:f101:0:0:0:1/64\n\n");
};

/* function formats an given IPv6 address to an uncompressed format
 *  not touching prefix length
 *  
 * examples:
 *  3ffe:400:100:f101::1 -> 3ffe:400:100:f101:0:0:0:1
 *  3ffe:400:100:f101::1/64 -> 3ffe:400:100:f101:0:0:0:1/64
 *
 * in : *addrstring = IPv6 address, unsigned int formatselector
 * out: *resultstring = result
 * ret: ==0: ok, !=0: error
 */
int addr2uncompaddr(char *addrstring, char *resultstring, unsigned int formatselector) {
	int retval = 1;
	char *addronlystring, tempstring[NI_MAXHOST], cnt, *cp, *op;
	int prefixlength = 0, flag_prefixlength = 0, result; 
	ipv6calc_ipv6addr ipv6addr;

#ifdef DEBUG_addr2uncompaddr
	fprintf(stderr, "addr2uncompaddr: Got input %s\n", addrstring);
#endif

	/* save prefix length first, if available */
    addronlystring = strtok (addrstring, "/");
    cp = strtok (NULL, "/");
	if ( cp != NULL ) {
		prefixlength = atol(cp);
		if (prefixlength < 0 || prefixlength > 128 ) {
			sprintf(resultstring, "illegal prefix length");
			retval = 1;
		return (retval);
		}
		flag_prefixlength = 1; 
	}

	if (strstr(addronlystring, "::")) {
#ifdef DEBUG_addr2uncompaddr
		fprintf(stderr, "addr2uncompaddr: Found '::' in IPv6 address\n");
#endif
		cnt = 0;
		cp = addronlystring;
		op = resultstring;
	   	while (*cp) {
			if (*cp == ':')	cnt += 1;
			if (*cp++ == '.') {
				cnt += 1;
				break;
			};
	    };
		cp = addrstring;
		while (*cp) {
			*op++ = *cp++;
			if (*(cp-1) == ':' && *cp == ':') {
				if ((cp-1) == addrstring) {
					op--;
					*op++ = '0';
					*op++ = ':';
				};
		   		*op++ = '0';
				while (cnt++ < 7) {
					*op++ = ':';
					*op++ = '0';
				}
			}
		}
		if (*(op-1)==':') *op++ = '0';
		*op = '\0';

		if ( flag_prefixlength == 1 ) {
			sprintf(resultstring, "%s/%d", resultstring, prefixlength);
		}
#ifdef DEBUG_addr2uncompaddr
		fprintf(stderr, "addr2uncompaddr: Result: %s\n", resultstring);
#endif
	};

	strcpy(tempstring, resultstring);

	result = uncomp2ipv6calc_ipv6addr(tempstring, resultstring, ipv6addr);
#ifdef DEBUG_addr2uncompaddr
	fprintf(stderr, "addr2uncompaddr: result of uncomp2ipv6calc_ipv6addr: %d\n", result);
#endif

	ipv6calc_ipv6addr_maskprefix(ipv6addr);
   
	retval = 0;
	return (retval);
}
