/* -------------------------------------------------------------------- */
/* SMS Client, send messages to mobile phones and pagers		*/
/*									*/
/* generic.c								*/
/*									*/
/*  Copyright (C) 1998,1999 Angelo Masci				*/
/*									*/
/*  This library is free software; you can redistribute it and/or	*/
/*  modify it under the terms of the GNU Library General Public		*/
/*  License as published by the Free Software Foundation; either	*/
/*  version 2 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	*/
/*  Library General Public License for more details.			*/
/*									*/
/*  You should have received a copy of the GNU Library General Public	*/
/*  License along with this library; if not, write to the Free		*/
/*  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.	*/
/*									*/
/*  You can contact the author at this e-mail address:			*/
/*									*/
/*  angelo@styx.demon.co.uk						*/
/*									*/
/* -------------------------------------------------------------------- */
/* $Id$
   -------------------------------------------------------------------- */

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

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

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

#if !defined(MSERVICEDIR)
#error "MSERVICEDIR undefined"
#else
#define SERVICEDIR        MSERVICEDIR
#endif

/* -------------------------------------------------------------------- */
/* The 'env' structure contains Service level data to be used for	*/
/* sending a message.							*/
/* -------------------------------------------------------------------- */

static struct generic_env
{
	DRIVER_DEFAULT_ENV def;

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

	TOKEN_HEAP 
		*heap;
	char	*script_file,
		*dialer;

} 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,       1200, &(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,       0,    &(driver_env.def.max_deliver)  	},

		{ RESOURCE_STRING,  "SMS_dialer", 		0, 1, NULL, 0,  "tcpip",     0,   &(driver_env.dialer)  	 	},
		{ RESOURCE_STRING,  "SMS_script_file", 		0, 1, NULL, 0,  NULL,        0,   &(driver_env.script_file)  	 	},
		{ RESOURCE_STRING,  "SMS_server_name", 		0, 1, NULL, 0,  "localhost", 0,   &(driver_env.def.server_name)		},
		{ RESOURCE_NUMERIC, "SMS_server_port", 		0, 1, NULL, 0,  NULL, 	     444, &(driver_env.def.server_port)		},
		{ 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)
#define SCRIPT_FILE		(driver_env.script_file)

/* -------------------------------------------------------------------- */
/* The following defines are used to signify errors			*/
/* occuring during the dialogue between the driver and the		*/
/* service centre. This number will be returned as the delivery		*/
/* value for the message that was aborted				*/
/*									*/
/* The defines MUST be placed in 'error.h'				*/

#define EGENERIC_NONUMBER 	250
#define EGENERIC_NOMESSAGE	251
#define EGENERIC_NODELIVERY	252

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

static 	char 	*generic_message = NULL,
		*generic_id	 = NULL;

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

static void GENERIC_hangup(void);
static int GENERIC_login(void);
static int GENERIC_send_disconnect(void);
static int GENERIC_sendmessage(char *msisdn, char *message);
static int GENERIC_dial(DRIVER_DEFAULT_ENV *env);
static void GENERIC_wrapper_hangup(DRIVER_DEFAULT_ENV *env);
static int using_modem_dialer(void);
static int using_tcpip_dialer(void);

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int using_modem_dialer(void)
{	return (strcmp(driver_env.dialer, "modem") == 0);
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int using_tcpip_dialer(void)
{	return (strcmp(driver_env.dialer, "tcpip") == 0);
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int GENERIC_dial(DRIVER_DEFAULT_ENV *env)
{
	if (using_modem_dialer())
	{	return default_dial(env);
	}
	else
	if (using_tcpip_dialer())
	{
		return default_tcpip_connect(env);
	}
	else
	{	lprintf(LOG_ERROR, "dial() failed,  using unsupported dialer '%s'\n", driver_env.dialer);
		return -1;
	}

	lprintf(LOG_STANDARD, "Connection Established.\n");
	return 0;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int GENERIC_init(char *mservice, DEVICE_ENTRY *device)
{
	if (default_init(mservice, device) == -1)
	{	return -1;
	}

	if (SCRIPT_FILE == NULL)
	{
		lprintf(LOG_ERROR, "Failed to initialize driver\n");
		return -1;
	}

	driver_env.heap = gs_parse_file(SCRIPT_FILE);
	if (driver_env.heap == NULL)
	{
		lprintf(LOG_ERROR, "Unrecoverable Failure Parsing file '%s'\n", SCRIPT_FILE);
		return -1;
	}

	return 0;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int process_list(TOKEN_HEAP *current_heap)
{
	int 	i, j;
	char 	*str,
		buf[1024];

	TOKEN_HEAP
		*tmp_heap,
		*heap;


	i = 0;
	while(TRUE)
	{
		heap = get_varlist_element(current_heap, i);
		if (heap == NULL)
		{	return 0;
		}

		str = get_strvalue(heap, "message");
		if (str != NULL)
		{	
			if (strlen(str) != 0)
			{	lprintf(LOG_STANDARD, str);
			}
		}


		tmp_heap = get_varlist(heap, "send");
		if (tmp_heap == NULL)
		{
			str = get_strvalue(heap, "send");
			if (str != NULL)
			{	
				if (strlen(str) != 0)
				{
					if (strcmp(str, "$MSG$") == 0)
					{
						if (generic_message != NULL)
						{	twrite(FD, generic_message, strlen(generic_message), WRITETIMEOUT);	
						}
					}
					else
					if (strcmp(str, "$ID$") == 0)
					{
						if (generic_id != NULL)
						{	twrite(FD, generic_id, strlen(generic_id), WRITETIMEOUT);	
						}
					}
					else
					{	twrite(FD, str, strlen(str), WRITETIMEOUT);	
					}
				}
			}
		}
		else
		{	j = 0;
			while((str = get_strvalue_element(tmp_heap, j)) != NULL)
			{
				if (str != NULL)
				{	
					if (strlen(str) != 0)
					{
						if (strcmp(str, "$MSG$") == 0)
						{
							if (generic_message != NULL)
							{	twrite(FD, generic_message, strlen(generic_message), WRITETIMEOUT);	
							}
						}
						else
						if (strcmp(str, "$ID$") == 0)
						{
							if (generic_id != NULL)
							{	twrite(FD, generic_id, strlen(generic_id), WRITETIMEOUT);	
							}
						}
						else
						{	twrite(FD, str, strlen(str), WRITETIMEOUT);	
						}
					}
				}

				j++;
			}
		}



		str = get_strvalue(heap, "expect");
		if (str != NULL)
		{	


		if (expstr(FD, buf, str, 1024, TIMEOUT) == 0)
		{
			tmp_heap = get_varlist(heap, "success");
			if (tmp_heap == NULL)
			{
				str = get_strvalue(heap, "success");
				if (str != NULL)
				{
					lprintf(LOG_STANDARD, str);
				}
			}
			else
			{	if (process_list(tmp_heap))
				{	return -1;
				}
			}
		}
		else
		{	tmp_heap = get_varlist(heap, "failure");
			if (tmp_heap == NULL)
			{
				str = get_strvalue(heap, "failure");
				if (str != NULL)
				{	
					lprintf(LOG_STANDARD, str);
				}


				return -1;
			}
			else
			{	if (process_list(tmp_heap))
                                {       return -1;
                                }
			}	
		}


		}


		i++;
	}
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int process_script_list(TOKEN_HEAP *current_heap, char *listname)
{
	TOKEN_HEAP
		*heap;


	heap = get_varlist(current_heap, listname);
	if (heap == NULL)
	{	return 0;
	}

	return process_list(heap);
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int GENERIC_login(void)
{	return process_script_list(driver_env.heap, "login");
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int GENERIC_sendmessage(char *msisdn, char *message)
{
	generic_message = message;
	generic_id	= msisdn;

	return process_script_list(driver_env.heap, "send");
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int GENERIC_send_disconnect(void)
{	return process_script_list(driver_env.heap, "disconnect");
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static void GENERIC_hangup(void)
{
	if (using_modem_dialer())
	{	default_hangup((DRIVER_DEFAULT_ENV *)(&driver_env));
	}
	else
	if (using_tcpip_dialer())
	{	TCPIP_disconnect(FD);
	}
	else
	{	lprintf(LOG_ERROR, "hangup() failed,  using unsupported dialer '%s'\n", driver_env.dialer);
	}
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static void GENERIC_wrapper_hangup(DRIVER_DEFAULT_ENV *env)
{	GENERIC_hangup();
}

/* -------------------------------------------------------------------- */
/* The following structure is used by core driver code. 		*/
/* The diagram below shows the call sequence of the functions.		*/
/* -------------------------------------------------------------------- */
DEVICE_ENTRY generic_device = {

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

	GENERIC_init,				/* Init			*/ 
	default_main,				/* Main			*/
	default_validate_always_true,		/* Validation		*/
	GENERIC_dial,				/* Dial			*/
	GENERIC_wrapper_hangup,			/* Hangup		*/
	GENERIC_send_disconnect,		/* Disconnect		*/
	default_single_deliver,			/* Deliver 		*/
	GENERIC_sendmessage,			/* Send			*/
	GENERIC_login				/* Login		*/
};

