/* -------------------------------------------------------------------- */
/* SMS Client, send messages to mobile phones and pagers		*/
/*									*/
/* driver.c								*/
/*									*/
/*  Copyright (C) 1997,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: driver.c,v 5.1 1998/02/01 07:10:39 root Exp $
   -------------------------------------------------------------------- */

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

#if defined(MODEMLIB) && (MODEMLIB == LIBMODEM)
#include <termios.h>
#include <dial/modems.h>
#else
#include "comms/comms.h"
#endif

#include "common/common.h"
#include "logfile/logfile.h"
#include "driver.h"
#include "driver_comms.h"
#include "error.h"
#include "parser/gs_translate.h"

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

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

/* -------------------------------------------------------------------- */
/* The 'device_list' is simply and array of pointer to device entry	*/
/* structures. If you write a new device you MUST add it's		*/
/* device structure to this list.					*/
/* -------------------------------------------------------------------- */

DEVICE_ENTRY *device_list[] = {
#if defined(TAP)
	&tap_device,
#endif
#if defined(VODAFONE)
	&vodafone_device,
#endif
#if defined(ORANGE)
	&orange_device,
#endif
#if defined(PAGEONE)
	&pageone_device,
#endif
#if defined(VODACOM)
	&vodacom_device,
#endif
#if defined(MTN)
	&mtn_device,
#endif
#if defined(ONE2ONE)
	&one2one_device,
#endif
#if defined(LIBERTEL)
	&libertel_device,
#endif
#if defined(TIM)
	&tim_device,
#endif
#if defined(SNPP)
	&snpp_device,
#endif
#if defined(CIMD)
	&cimd_device,
#endif
#if defined(VODAPAGE_BLOCK)
	&vodapage_block_device,
#endif
#if defined(PROXIMUS)
	&proximus_device,
#endif
#if defined(KPN)
	&kpn_device,
#endif
#if defined(ANSWER)
	&answer_device,
#endif
#if defined(GENERIC)
	&generic_device,
#endif
#if defined(UCP)
	&ucp_device,
#endif
#if defined(UCP_TCP)
	&ucp_tcp_device,
#endif
#if defined(WWW)
	&www_device,
#endif
#if defined(ORANGE_WEB)
	&orange_web_device,
#endif
#if defined(LYCOS_WEB)
	&lycos_web_device,
#endif
#if defined(CELLNET_WEB)
	&cellnet_web_device,
#endif
#if defined(PROXIMUS_WEB)
	&proximus_web_device,
#endif
#if defined(ATT_WEB)
	&att_web_device,
#endif
#if defined(NEXTEL_WEB)
	&nextel_web_device,
#endif
#if defined(PAGENET_WEB)
	&pagenet_web_device,
#endif
#if defined(MOBISTAR)
	&mobistar_device,
#endif
	NULL
};

/* -------------------------------------------------------------------- */
/* Return a device entry structure by supplying its name.		*/
/* -------------------------------------------------------------------- */
DEVICE_ENTRY *get_device(char *name)
{
	DEVICE_ENTRY **device;


	if (name == NULL)
	{	return NULL;
	}

	
	device = device_list;

	while (*device != NULL)
	{
		if ((*device)->name != NULL)
		{	if (strcmp((*device)->name, name) == 0)
			{
				lprintf(LOG_VERBOSE, "Device Found: %s\n", name);
				return *device;
			}
		}

		device++;
	}

	lprintf(LOG_VERBOSE, "Device NOT Found: %s\n", name);
	return NULL;
}


/* -------------------------------------------------------------------- */
/* List all the device entries currently compiled in.			*/
/* -------------------------------------------------------------------- */
void display_drivers(void)
{
	DEVICE_ENTRY **device;


	device = device_list;

	if (*device == NULL)
	{	lprintf(LOG_WARNING, "No drivers have been included!\n");
	}

	while (*device != NULL)
	{
		lprintf(LOG_STANDARD, "%s %s\n",
			((*device)->name != NULL)?(*device)->name:"<NULL>",
			((*device)->version_string != NULL)?(*device)->version_string:"<NULL>");

		device++;
	}
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_dial(DRIVER_DEFAULT_ENV *env)
{
	lprintf(LOG_STANDARD, "Dialing SMSC %s...\n", env->centre_number);
	
	env->fd = SMS_dial(env->centre_number, env->comms_params, env->baud);
	if (env->fd < 0)
	{ 	lprintf(LOG_WARNING, "Failed to connect\n"); 
		return EDIAL;
	}

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


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_tcpip_connect(DRIVER_DEFAULT_ENV *env)
{
	lprintf(LOG_STANDARD, "Connecting to Server %s:%ld...\n", 
		env->server_name, 
		env->server_port);
	
	env->fd = TCPIP_connect(env->server_name,
	                        env->server_port);
	if (env->fd < 0)
	{ 	lprintf(LOG_WARNING, "Failed to Connect.\n"); 
		return EDIAL;
	}

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


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
void default_tcpip_disconnect(DRIVER_DEFAULT_ENV *env)
{
	lprintf(LOG_STANDARD, "Disconnecting...\n");
	TCPIP_disconnect(env->fd);
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
void default_hangup(DRIVER_DEFAULT_ENV *env)
{
	lprintf(LOG_STANDARD, "Hangup...\n");
	SMS_hangup(env->fd);

	env->connection_status = SERVICE_NOT_CONNECTED;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
void default_main(void *list,
                  void *(* get_first)(void *list),
                  void *(* get_next)(void *list),
                  char *(* get_number)(void *node),
                  char *(* get_message)(void *node),
                  void (* set_delivery)(void *node, int result),
                  DRIVER_DEFAULT_ENV *env)
{
	void	*node;
	char	*msisdn,
		*message;
	int	result;


	lprintf(LOG_VERBOSE, "%s %s driver called\n", 
		(env->device->name != NULL)?env->device->name:"<NULL>",
		(env->device->version_string != NULL)?env->device->version_string:"<NULL>");



	env->connection_status = SERVICE_NOT_CONNECTED;
	result = 0;
	
	node = (* get_first)(list);
	while (node != NULL)
	{
		msisdn  = (* get_number)(node);
		message = (* get_message)(node);


		result = (* env->device->deliver)(msisdn, message, env);
		(* set_delivery)(node, result);

		if (result)
		{	(* env->device->hangup)(env);

			env->connection_status = SERVICE_NOT_CONNECTED;
		}

		node = (* get_next)(node);
	}

	if ((result == 0) && (env->connection_status == SERVICE_CONNECTED))
	{
		(* env->device->disconnect)();
		(* env->device->hangup)(env);

		env->connection_status = SERVICE_NOT_CONNECTED;
	}
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_multiple_deliver(char *msisdn, char *message, DRIVER_DEFAULT_ENV *env)
{
	int 	error;


	if (env->connection_status == SERVICE_NOT_CONNECTED)
	{
		env->connection_status = SERVICE_CONNECTED;

	 	error = (* env->device->dial)(env);
		if (error)
		{	return error;
		}

		error = (* env->device->login)();
		if (error)
		{	return error;
		}
	}

	error = (* env->device->sendmessage)(msisdn, message);
	if (error)
	{	return error;
	}

	return 0;
}

/* -------------------------------------------------------------------- */
/* Send as many messages as we are allowed.				*/
/* Keep track of number of messages sent and compare against		*/
/* Max allowed, disconnecting when number sent reaches			*/
/* the max allowed.							*/
/* -------------------------------------------------------------------- */
int default_multiple_counted_deliver(char *msisdn, char *message, DRIVER_DEFAULT_ENV *env)
{
	int 	error;


	if (env->connection_status == SERVICE_NOT_CONNECTED)
	{
		env->num_sent          = 0;
		env->connection_status = SERVICE_CONNECTED;

	 	error = (* env->device->dial)(env);
		if (error)
		{	return error;
		}

		error = (* env->device->login)();
		if (error)
		{	return error;
		}
	}

	error = (* env->device->sendmessage)(msisdn, message);
	if (error)
	{	return error;
	}


	env->num_sent++;

	lprintf(LOG_VERBOSE, "Num sent    = %ld\n", env->num_sent);
	lprintf(LOG_VERBOSE, "Max deliver = %ld\n", env->max_deliver);

	if ((env->max_deliver != 0) && 
	    (env->num_sent >= env->max_deliver))
	{
		(* env->device->disconnect)();
		(* env->device->hangup)(env);

		env->connection_status = SERVICE_NOT_CONNECTED;
	}

	return 0;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_send_disconnect(void)
{	return 0;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_single_deliver(char *msisdn, char *message, DRIVER_DEFAULT_ENV *env)
{
	int 	error;
	

	env->connection_status = SERVICE_CONNECTED;

	error = (* env->device->dial)(env);
	if (error)
	{	return error;
	}

	error = (* env->device->login)();
	if (error)
	{	return error;
	}

	error = (* env->device->sendmessage)(msisdn, message);
	if (error)
	{	return error;
	}

	(* env->device->disconnect)();
	(* env->device->hangup)(env);

	env->connection_status = SERVICE_NOT_CONNECTED;
	return 0;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_validate_numeric_id(char *ptr)
{
	while (*ptr != '\0')
	{
		if (!isdigit(*ptr))
		{	return FALSE;
		}

		ptr++;
	}

	return TRUE;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_validate_always_true(char *id)
{	return TRUE;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_init(char *mservice, DEVICE_ENTRY *device)
{
	char fname[1024];

	strcpy(fname, SERVICEDIR);
	libcommon_strfcat(fname, "services");
	libcommon_strfcat(fname, mservice);

	if (read_resource_file(fname, device->resource_list, TRUE) != RESOURCE_FILE_OK)
	{
		lprintf(LOG_ERROR, "Unrecoverable Failure Parsing file '%s'\n", fname); 
		return -1;
	}

	device->env->device = device;
	return 0;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_login(void)
{	return 0;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int default_sendmessage(char *msisdn, char *message)
{	return 0;
}

/* -------------------------------------------------------------------- */
/* Search 'sms_services' for 'service' and return 'protocol'		*/
/* -------------------------------------------------------------------- */
char *get_protocol(char *service)
{
	char 	fname[1024],
		*protocol;

	TOKEN_HEAP
		*heap;

	strcpy(fname, SERVICEDIR);
	libcommon_strfcat(fname, "sms_services");

	heap = gs_parse_file(fname);
	if (heap == NULL)
	{
		lprintf(LOG_ERROR, "Parsing file '%s'\n", fname);
		exit(-1);
	}

	protocol = get_strvalue(heap, service);
	if (protocol == NULL)
	{
		lprintf(LOG_VERBOSE, "Service '%s' Not Found\n", service);

		free_heap(heap);
		return NULL;
	}

	lprintf(LOG_VERBOSE, "Service '%s' using protocol '%s'\n", service, protocol);
	return strdup(protocol);
}


