/********************************* (C) РОТЕК ***********************************
 * @module  template
 * @file    template.c
 * @version 1.0.0
 * @date    XX.XX.XXXX
 * $brief   template
 *******************************************************************************
 * @history     Version  Author         Comment
 * XX.XX.XXXX   1.0.0    Telenkov D.A.  First release.
 *******************************************************************************
 */

#include "stm32f4xx.h"  
#include "radius_user.h"

#include "FreeRTOS.h"
#include "task.h"

#include "freeradius-client.h"
#include "fr_options.h"

rc_handle	rcHandle;

int auth_order = AUTH_LOCAL_SND;
int login_tries = 4;
int login_timeout = 60;
char* nologin = "?";
char* issue = "?";
char* authserver = "192.168.1.2:1645";
char* acctserver = "0";
char* servers = "?";
char* dictionary = "?";
char *login_radius = "?";
char *mapfile = "?";
char *default_realm = NULL;
int radius_timeout = 10;
int radius_retries = 3;
int radius_deadtime = 0;
char *bindaddr = "*";
char *login_local = "?";

OPTION      rcOptions[] = {
{"auth_order",	 	OT_AUO, ST_UNDEF, (void*)&auth_order}, // AUTH_LOCAL_FST AUTH_RADIUS_FST AUTH_LOCAL_SND AUTH_RADIUS_SND
{"login_tries",	 	OT_INT, ST_UNDEF, (void*)&login_tries},
{"login_timeout",	OT_INT, ST_UNDEF, (void*)&login_timeout},
{"nologin",		    OT_STR, ST_UNDEF, NULL},
{"issue",		    OT_STR, ST_UNDEF, NULL},
// RADIUS specific options 
{"authserver",		OT_SRV, ST_UNDEF, (void*)&authserver},
{"acctserver",		OT_SRV, ST_UNDEF, (void*)&acctserver},
{"servers",		    OT_STR, ST_UNDEF, (void*)&servers},
{"dictionary",		OT_STR, ST_UNDEF, (void*)&dictionary},
{"login_radius",	OT_STR, ST_UNDEF, (void*)&login_radius},
{"mapfile",		    OT_STR, ST_UNDEF, (void*)&mapfile},
{"default_realm",	OT_STR, ST_UNDEF, (void*)&default_realm},
{"radius_timeout",	OT_INT, ST_UNDEF, (void*)&radius_timeout},
{"radius_retries",	OT_INT,	ST_UNDEF, (void*)&radius_retries},
{"radius_deadtime",	OT_INT, ST_UNDEF, (void*)&radius_deadtime},
{"bindaddr",		OT_STR, ST_UNDEF, (void*)&bindaddr},
// local options 
{"login_local",		OT_STR, ST_UNDEF, (void*)&login_local},
};

static DICT_ATTR   attr_1;
static DICT_ATTR   attr_2;
static DICT_ATTR   attr_3;

static char rc_msg[PW_MAX_MSG_SIZE];


RadiusClientResult RC_Login(char* login, char* pas)
{
    VALUE_PAIR* send;
    VALUE_PAIR* received;
    uint32_t	service;
    
    int result;
    
    memset(rc_msg, 0, PW_MAX_MSG_SIZE);

    memset(&rcHandle, 0, sizeof(rc_handle));
  
    rc_read_config(&rcHandle);
    
    // Формирование атрибутов
    // 1. User name
    strncpy(attr_1.name, login, strlen(login));
    attr_1.value = 1;
    attr_1.type = PW_TYPE_STRING;
    attr_1.next = NULL;
    
    // 2. Password
    strncpy(attr_2.name, pas, strlen(pas));
    attr_2.value = 2;
    attr_2.type = PW_TYPE_STRING;
    attr_2.next = &attr_1;
    
    // 3. Service type
    strcpy(attr_3.name, "Service-Type");
    attr_3.value = 6;
    attr_3.type = PW_TYPE_INTEGER;
    attr_3.next = &attr_2;
    
    rcHandle.dictionary_attributes = &attr_3;
    
    send = NULL;
    
	// User-Name
    if (rc_avpair_add(&rcHandle, &send, PW_USER_NAME, login, -1, 0) == NULL)
		return RC_ERROR;
    
	// User-Password
	if (rc_avpair_add(&rcHandle, &send, PW_USER_PASSWORD, pas, -1, 0) == NULL)
		return RC_ERROR;
	
	// Service-Type
	service = PW_AUTHENTICATE_ONLY;
	if (rc_avpair_add(&rcHandle, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL)
		return RC_ERROR;

    result = rc_auth(&rcHandle, 0, send, &received, rc_msg);
    
    switch (result)
    {
    case USER_RC :
        return RC_LOGIN_USER_OK;
    break;
    
    case ADMIN_RC :
        return RC_LOGIN_ADMIN_OK;
    break;
    
    case NET_ERR_RC :
        return RC_NET_ERR;
    break;
    
    case ERROR_RC :
        return RC_ERROR;
    break;
    
    case BADRESP_RC :
        return RC_ACC_DENIED;
    break;
    
    case REJECT_RC :
        return RC_ACC_DENIED;
    break;
    
    default :
        return RC_ERROR;
    break;
    }
    return RC_ERROR;
    //printf("\r\n");
    //printf("Radius client result: %i\r\n", result);
    
}

/**
  * @brief  
  */
int RD_TestInit(void)
{
    int         result;
	char		username[128];
	char        passwd[AUTH_PASS_LEN + 1];
	VALUE_PAIR 	*send, *received;
	uint32_t	service;
	char 		msg[PW_MAX_MSG_SIZE], username_realm[256];
	char		*default_realm;
	  
    // Моя подготовка 
    memset(username, 0, 128);
    memset(passwd, 0, AUTH_PASS_LEN + 1);
    memset(msg, 0, PW_MAX_MSG_SIZE);
    memset(username_realm, 0, 256);
    
    
    // Просто копируем структуру настроек которая жесто задана
    rc_read_config(&rcHandle);
   
    // Словарь пока опускаем и не инициализируем
    //if (rc_read_dictionary(&rcHandle, rc_conf_str(&rcHandle, "dictionary")) != 0)
	//	return ERROR_RC;
  
    // Заполняем словарь
    // 1. User name
    strcpy(attr_1.name, "test1");
    attr_1.value = 1;
    attr_1.type = PW_TYPE_STRING;
    attr_1.next = NULL;
    
    // 2. Password
    strcpy(attr_2.name, "12345");
    attr_2.value = 2;
    attr_2.type = PW_TYPE_STRING;
    attr_2.next = &attr_1;
    
    // 3. Service type
    strcpy(attr_3.name, "Service-Type");
    attr_3.value = 6;
    attr_3.type = PW_TYPE_INTEGER;
    attr_3.next = &attr_2;
    
/*    
    attr_3.value = 244;
    attr_3.type = PW_TYPE_STRING;
    attr_3.next = &attr_2;
*/    
    rcHandle.dictionary_attributes = &attr_3;
    
    // Не понял что за параметра, пока NULL
    //default_realm = rc_conf_str(rh, "default_realm");
    default_realm = NULL;

    // Рараметры ожидаются от пользователя
    //strncpy(username, "dtelenkov", 9);
    strncpy(username, "test1", 5);
    strncpy(passwd, "12345", 5);
    //strncpy(username, rc_getstr (rh, "login: ",1), sizeof(username));
	//strncpy (passwd, rc_getstr(rh, "Password: ",0), sizeof (passwd));
    
    send = NULL;
        
    /*
	 * Fill in User-Name
	 */

	strncpy(username_realm, username, sizeof(username_realm));

	/* Append default realm */
    /*
	if ((strchr(username_realm, '@') == NULL) && default_realm &&
	    (*default_realm != '\0'))
	{
		strncat(username_realm, "@", sizeof(username_realm)-strlen(username_realm)-1);
		strncat(username_realm, default_realm, sizeof(username_realm)-strlen(username_realm)-1);
	}
    */
    
	if (rc_avpair_add(&rcHandle, &send, PW_USER_NAME, username_realm, -1, 0) == NULL)
		return ERROR_RC;
    
	/*
	 * Fill in User-Password
	 */
	if (rc_avpair_add(&rcHandle, &send, PW_USER_PASSWORD, passwd, -1, 0) == NULL)
		return ERROR_RC;

	/*
	 * Fill in Service-Type
	 */
	service = PW_AUTHENTICATE_ONLY;
	if (rc_avpair_add(&rcHandle, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL)
		return ERROR_RC;
#if 0
	result = rc_auth(&rcHandle, 0, send, &received, msg);

	if (result == OK_RC)
	{
		fprintf(stderr, "\"%s\" RADIUS Authentication OK\n", username);
	}
	else
	{
		fprintf(stderr, "\"%s\" RADIUS Authentication failure (RC=%i)\n", username, result);
	}

	
#endif
	send = NULL;
    
    return 0;
}

void initFdsets(fdsets *sets)
{
    memset((sets)->buf1, 0xab, 8); 
    memset((sets)->buf2, 0xab, 8); 
    memset((sets)->buf3, 0xab, 8); 
    memset((sets)->buf4, 0xab, 8); 
}

bool recvSelect(fdsets *sets, int *socket, uint32_t timeout)
{
    struct timeval tv;

    tv.tv_sec = 0;
    tv.tv_usec = timeout * 1000;
      
    FD_ZERO(&(sets->readset));
    FD_SET(*socket, &sets->readset);
    FD_ZERO(&sets->errset);
    FD_SET(*socket, &sets->errset);
        
    lwip_select(*socket + 1, &sets->readset, NULL, &sets->errset, &tv);
        
    if (FD_ISSET(*socket, &sets->readset)) 
        return true;

    return false;
}

//
int RC_GetAccessRights(char* buf)
{
    uint16_t tmpLen = 0;
    uint8_t att = 10;
    
    while (att)
    {
        att--;  // Предохранитель
        
        if (strstr(buf, "user") != 0) {
            return USER_RC; }
        else if (strstr(buf, "admin") != 0) {
            return ADMIN_RC; }
        
        tmpLen = strlen(buf);
        buf += tmpLen + 1;            
    }
    
    return ERROR_RC;
}


/********************************* (C) РОТЕК **********************************/
