// This program is free software; you can redistribute it and/or
// modify it under the terms of the BUT OPEN SOURCE LICENCE
// Version 1 as published by the Brno University of Technology, Antonínská 548/1,
// 601 90, Czech Republic.
// 
// This program 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
// BUT OPEN SOURCE LICENCE (BUTOSL) for more details.
// 
// You should have received a copy of the BUT OPEN SOURCE LICENCE (BUTOSL)
// along with this program; if not, write to the Brno University of Technology,
// Antonínská 548/1, 601 90, Czech Republic.




extern "C" {
#include <stdio.h>
}

#include "radius.h"

bool Radius_Attribute::decode(Buffer &pkt)
{
	Octet null;
	pkt.get_octet(_len);

	//skip uknown bytes
	for(int i=2; i<_len;i++){
		pkt.get_octet(null);
	}
	//printf("EATED %i!\n",_len);
	return true;
};


bool Radius_Attr_User_Name::decode(Buffer &pkt)
{
	pkt.get_octet(_len);

	int l = 2;
	Octet c =0;
	while( l < _len){
		pkt.get_octet(c);
		_user_name.append(1,(char) c);
		l++;
	}
	//cout << "Radius: user_name = " << _user_name <<endl;
	return true;
}


bool Radius_Attr_Framed_IP_Address::decode(Buffer &pkt)
{
	pkt.get_octet(_len);
	_address.decode(pkt);
	//cout << "Radius: ipv4 address = " << _address.to_string() <<endl;
	return true;
}

bool Radius_Attr_Framed_IPv6_Prefix::decode(Buffer &pkt)
{
	Octet reserved;
	pkt.get_octet(_len);
	pkt.get_octet(reserved); // reserved
	pkt.get_octet(_prefix_len);
	_address.decode(pkt,_prefix_len);
	//cout << "Radius: ipv6 prefix = " << _address.to_string() <<endl;
	return true;
}

bool Radius_Attr_Calling_Station_Id::decode(Buffer &pkt)
{
	pkt.get_octet(_len);

	int l = 2;
	Octet c =0;
	while( l < _len){
		pkt.get_octet(c);
		_id.append(1,(char) c);
		l++;
	}
	//cout << "Radius: station id = " << _id <<endl;
	return true;
}

bool Radius_Attr_Framed_Interface_Id::decode(Buffer &pkt)
{
	pkt.get_octet(_len);

	Octet c =0;
	for(int i=0; i<MAX_SIZE; i++){
		pkt.get_octet(c);
		_interface_id[i]= c;
	}
	//cout << "Radius: station id = " << interface_id() <<endl;
	return true;
}

string Radius_Attr_Framed_Interface_Id::interface_id()
{
	string rval = "";
	char buf[6];
	for(int i=0; i<MAX_SIZE; i++){
		sprintf(buf, "%x", _interface_id[i]);
		rval+=buf;
	}
	return rval;
}

Radius_Attribute *Radius_Attribute::decode_attribute(Buffer &pkt)
{
	Radius_Attribute *opt=NULL;
	Octet type = 0;
	pkt.get_octet(type);

	switch (type){
	case 0: return NULL; break;
	case USER_NAME: opt = new Radius_Attr_User_Name;break;
	case FRAMED_IP_ADDRESS: opt = new Radius_Attr_Framed_IP_Address;break;
	case CALLING_STATION_ID: opt = new Radius_Attr_Calling_Station_Id;break;
	case FRAMED_IPV6_PREFIX: opt = new Radius_Attr_Framed_IPv6_Prefix;break;
	case FRAMED_INTERFACE_ID: opt = new Radius_Attr_Framed_Interface_Id;break;
	default: opt = new Radius_Attribute;break;
	}

	if(opt->decode(pkt)){
		//printf("attribute -> type: %i name: %s\n",type, opt->name().c_str());
		return opt;
	}
	delete opt;
	return NULL;

};


Radius_Attribute *Radius::attribute(int i){
	if (i<MAX_OPTS && i >= 0 && i<_opts_cnt)
		return _opts[i];
	return NULL;
}

bool Radius::decode(Buffer &pkt)
{
	pkt.get_octet(_code);
	pkt.get_octet(_identifier);
	pkt.get_hshort(_len);

	int i=0;
	for(i=0;i<16;i++){
		pkt.get_octet(_authenticator[i]);
	}

	i=0;
	while(pkt.left()>0){ //TODO there can be padding!
		//printf("Attribute left: %i\n", pkt.left());
		if((_opts[i] = Radius_Attribute::decode_attribute(pkt)) == NULL ){
			printf("NULL\n");
			return false;
		}
		//printf("Option len: %i (%s)\n",_opts[i]->len(), _opts[i]->name().c_str());
		i++;
	}
	_opts_cnt = i; //number of decoded options;
	return true;
};

