/* -------------------------------------------------------------------- */
/* Variante del file ucp.c per sms_client 2.0.8r by JacK McKrak         */
/* -------------------------------------------------------------------- */

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include "common/common.h"
#include "logfile/logfile.h"
#include "driver.h"
#include "error.h"
#include "ascii.h"
#include "comms/comms.h"
#include "resource/resource.h"

/* -------------------------------------------------------------------- */

static struct ucp_env
{
	DRIVER_DEFAULT_ENV def;

	/* Place any extended driver	*/
	/* variables here 		*/

} driver_env;

/* -------------------------------------------------------------------- */

static 	RESOURCE resource_list[] =
	{
		{ RESOURCE_STRING,  "SMS_comms_params",
 	0, 1, NULL, 0,  "8N1",      0, 	  &(driver_env.def.comms_params)
  		},
		{ RESOURCE_STRING,  "SMS_centre_number", 	
	0, 1, NULL, 0,  NULL,       0, 	  &(driver_env.def.centre_number)
	  	},
		{ RESOURCE_NUMERIC, "SMS_baud", 		
	0, 1, NULL, 0,  NULL,       9600, &(driver_env.def.baud)
  		},
		{ RESOURCE_NUMERIC, "SMS_deliver_timeout", 	
	0, 0, NULL, 0,  NULL,       30,   &(driver_env.def.deliver_timeout)
	  	},
		{ RESOURCE_NUMERIC, "SMS_timeout",
 	0, 0, NULL, 0,  NULL,       10,   &(driver_env.def.timeout)
  		},
		{ RESOURCE_NUMERIC, "SMS_write_timeout",
 	0, 0, NULL, 0,  NULL,       10,   &(driver_env.def.write_timeout)
	  	},
		{ RESOURCE_NUMERIC, "SMS_max_deliver",
 		0, 0, NULL, 0,  NULL,       1,    &(driver_env.def.max_deliver)
	  	},
		{ RESOURCE_NULL,     NULL, 
		0, 1, NULL, 0,  NULL,       0,    NULL
  		}
	};

/* -------------------------------------------------------------------- */

#define DELIVERTIMEOUT 		(driver_env.def.deliver_timeout)
#define TIMEOUT 		(driver_env.def.timeout)
#define WRITETIMEOUT 		(driver_env.def.write_timeout)

/* -------------------------------------------------------------------- */

#define FD			(driver_env.def.fd)

/* -------------------------------------------------------------------- */

static int UCP_sendmessage(char *msisdn, char *message);
static int UCP_parse_response(char *string);
static void UCP_hangup(void);
static char *UCP_generate_checksum(const char *fmt, ...);
static char *UCP_build_message(char *msisdn, char *message);
static char *UCP_build_transaction(int transaction_id, char transaction_type,
                                   int operation_type, const char *fmt, ...);

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static char *UCP_generate_checksum(const char *fmt, ...)
{
	va_list args;
static 	char	buf[1024];
	char	*ptr;
	int	j;



	va_start(args, fmt);
#if !defined(LINUX)
	vsprintf(buf, fmt, args);
#else
	vsnprintf(buf, 1024, fmt, args);
#endif
	va_end(args);


	/* ------------------------ */

	j = 0;
	for (ptr = buf; *ptr != '\0'; ptr++)
	{
		j += *ptr;

		if (j >= 256)
		{	j -= 256;
		}
	}

	sms_snprintf(buf, 1024, "%02X", j);
	return buf;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static char *UCP_build_transaction(int transaction_id, char transaction_type,
                                   int operation_type, const char *fmt, ...)
{
	va_list args;
static	char	buf[1024];
	char	header[1024],
		data[1024],
		codestring[1024];

	FILE *fcd;


	va_start(args, fmt);
#if !defined(LINUX)
	vsprintf(data, fmt, args);
#else
	vsnprintf(data, 1024, fmt, args);
#endif
	va_end(args);

	/* ------------------------ */


	fcd = fopen("codice","r");
	fscanf(fcd,"%s",&codestring);
	fclose(fcd);

	sms_snprintf(header, 1024, "%02d/%05d/%c", transaction_id,
	   sms_strlen(data) + sms_strlen(codestring) + 15, transaction_type);

	printf("<STX>%s/%s/%s/%s<ETX>\n",header,codestring,
	     data,UCP_generate_checksum("%s/%s/%s/",header,codestring,data));

	sms_snprintf(buf, 1024, "%c%s/%s/%s/%s%c", S_STX,
	                             header,
	                             codestring,
	                             data,
	                             UCP_generate_checksum("%s/%s/%s/", 
					header, codestring, data),
	                             S_ETX);

	return buf;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static char *UCP_build_message(char *msisdn, char *message)
{
	char	ia5_message[1024],
		*src,
		*dest;


	dest = ia5_message;
	for (src = message; *src != '\0'; src++)
	{
		sms_snprintf(dest, 1024, "%02X", *src);
		dest += 2;
	}

	return UCP_build_transaction(1, 'O', 1, "%s", ia5_message);
}


/* -------------------------------------------------------------------- */
/* Return Values:							*/
/*	 0 Positive ACK 						*/
/*	 1 Negative ACK							*/
/*	-1 Error  							*/
/* -------------------------------------------------------------------- */
static int UCP_parse_response(char *string)
{
	int	result;

	int  	transaction,
 		length,
		type,
		checksum;

	char 	ack,
		recipient[64],
		timestamp[64];

	/* ------------------------------------------------------------ */
	/* Example:							*/
	/* <STX>01/00045/R/01/A/0041544180972:161298112313/A6<ETX> 	*/
	/* <STX>01/00019/R/01/A//69<ETX>				*/
	/* ------------------------------------------------------------ */

	result = sscanf(string, "\002%02d/%05d/R/%02d/%c/%16[^:]:%12s/%02X\003",
	                &transaction,
	                &length,
	                &type,
	                &ack,
	                recipient,
	                timestamp,
	                &checksum);

	if (result != 7)
	{
		result = sscanf(string, "\002%02d/%05d/R/%02d/%c//%02X\003",
		                &transaction,
		                &length,
		                &type,
		                &ack,
		                &checksum);

		if (result != 5)
		{	return -1;
		}
	}

	/* ---------------------------- */

	result = -1;

	if (ack == 'A')
	{	result = 0;
	}
	else
	if (ack == 'N')
	{	result = 1;
	}

	return result;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int UCP_sendmessage(char *msisdn, char *message)
{
	char 	buf[MAX_RESPONSE_BUFSIZE],
		*ucp_message;

	int	result;


	ucp_message = UCP_build_message(msisdn, message);
	twrite(FD, ucp_message, sms_strlen(ucp_message), WRITETIMEOUT);

	if (expstr(FD, buf, "\03", MAX_RESPONSE_BUFSIZE, DELIVERTIMEOUT) == 0)
	{
		lprintf(LOG_STANDARD, "SMSC Respsonse: %s\n", buf);

		result = UCP_parse_response(buf);
		if (result == 0)
		{
			lprintf(LOG_STANDARD, "Received Acknowledgement\n");
		}
		else
		if (result == 1)
		{	lprintf(LOG_STANDARD, "Acknowledgement Failed\n");

			UCP_hangup();
			return EUCP_ACKFAILED;
		}
		else
		{	lprintf(LOG_STANDARD, "Bad Acknowledgement\n");

			UCP_hangup();
			return EUCP_BADACK;
		}
	}
	else
	{	lprintf(LOG_STANDARD, "No Message Response\n");

		UCP_hangup();
		return EUCP_NORESPONSE;
	}

	return 0;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static void UCP_hangup(void)
{	default_hangup((DRIVER_DEFAULT_ENV *)(&driver_env));
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
DEVICE_ENTRY ucp_device = {

	"UCP",
	"1.0",
	resource_list,
	(DRIVER_DEFAULT_ENV *)(&driver_env),

	default_init,
	default_main,
	default_validate_numeric_id,
	default_dial,
	default_hangup,
	default_send_disconnect,
	default_single_deliver,
	UCP_sendmessage,
	default_login
};
