/* -------------------------------------------------------------------- */
/* SMS Client, send messages to mobile phones and pagers		*/
/*									*/
/* expand.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$
   -------------------------------------------------------------------- */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <stddef.h>

/* -------------------------------------------------------------------- */
/* The following should probably be moved to 'common/common.h'			*/
/* -------------------------------------------------------------------- */

#if defined(NEXT)
#include <sys/dir.h>
#include <sys/dirent.h>
#define NAME_MAX 255
#define PATH_MAX 1024
#else
#include <dirent.h>
#endif

#if defined(SOLARIS)
#define NAME_MAX FILENAME_MAX
#endif

#if defined(AIX)
#define NAME_MAX 512
#endif

#if defined(SCO)
#define NAME_MAX pathconf("/",_PC_NAME_MAX)
#define PATH_MAX pathconf("/",_PC_PATH_MAX)
#endif

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

#include "error.h"
#include "logfile/logfile.h"
#include "expand.h"
#include "sms_list.h"
#include "resource/resource.h"
#include "driver/driver.h"
#include "parser/gs_token.h"
#include "parser/gs_translate.h"

#include "common/common.h"

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

#if !defined(MLOCALSMSRC)
#error "MLOCALSMSRC undefined"
#else
#define LOCALSMSRC      MLOCALSMSRC
#endif

#if !defined(MGLOBALSMSRC)
#error "MGLOBALSMSRC undefined"
#else
#define GLOBALSMSRC     MGLOBALSMSRC
#endif

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

SMS_list *search_list;

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

static TOKEN_HEAP *SMS_open_global_smsrc(void);
static TOKEN_HEAP *SMS_open_local_smsrc(void);
static SMS_list *expandnumber(TOKEN_HEAP *global, TOKEN_HEAP *local, char *id, char *str, char *default_service);

static char *strdup_service(char *str);
static char *strdup_number(char *str);

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static TOKEN_HEAP *SMS_open_global_smsrc(void)
{
	lprintf(LOG_VERBOSE, "Opening Global Addressbook File: %s\n", GLOBALSMSRC);
	return gs_parse_file(GLOBALSMSRC);
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static TOKEN_HEAP *SMS_open_local_smsrc(void)
{
	TOKEN_HEAP *heap;
	struct passwd
		*pentry;

	char 	*filename;


	filename = (char *)malloc(sizeof(char) * (PATH_MAX + NAME_MAX +1));
	if (filename == NULL)
	{
		lprintf(LOG_ERROR, "malloc() Failed\n");
		exit(EMALLOC);
	}

	pentry = getpwuid(getuid());
	
	strcpy(filename, pentry->pw_dir);
	libcommon_strfcat(filename, LOCALSMSRC);

	lprintf(LOG_VERBOSE, "Opening Local Addressbook File: %s\n", filename);

	heap = gs_parse_file(filename);
	free(filename);

	return heap;
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
void SMS_dual_closerc(TOKEN_HEAP *global, TOKEN_HEAP *local)
{
	if (global != NULL)
	{	free_heap(global);
	}

	if (local != NULL)
	{	free_heap(local);
	}
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int SMS_dual_openrc(TOKEN_HEAP **global, TOKEN_HEAP **local)
{
	*local = SMS_open_local_smsrc();
	if (*local == NULL)
	{	lprintf(LOG_VERBOSE, "Failed to open local smsrc file\n");
	}

	*global = SMS_open_global_smsrc();
	if (*global == NULL)
	{	lprintf(LOG_WARNING, "Failed to open global smsrc file\n");

		SMS_dual_closerc(*global, *local);
		return -1;
	}

	return 0;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static char *strdup_service(char *str)
{
	char 	*ptr,
		*dst,
		*service;


	service = (char *)malloc(sizeof(char) * (strlen(str) +1));
	if (service == NULL)
	{
		lprintf(LOG_ERROR, "malloc() failed\n");
		exit(EMALLOC);
	}

	
	dst = service;
	ptr = str;
	while(*ptr != '\0')
	{

		if (*ptr == ':')
		{	*dst = '\0';
			break;
		}
		else
		{	*dst = *ptr;
		}
		
		dst++;		
		ptr++;
	}

	if (*ptr == '\0')
	{
		*service = '\0';
	}

	return service;	
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static char *strdup_number(char *str)
{
	char 	*ptr,
		*dst,
		*number;

	
	number = (char *)malloc(sizeof(char) * (strlen(str) +1));
	if (number == NULL)
	{
		lprintf(LOG_ERROR, "malloc() failed\n");
		exit(EMALLOC);
	}

	
	dst = number;
	ptr = str;
	while(*ptr != '\0')
	{
		if (*ptr == ':')
		{	dst = number;
		}
		else
		{	*dst = *ptr;
			dst++;		
		}
			
		ptr++;
	}

	*dst = '\0';
	
	return number;	
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
SMS_list *add_number(SMS_list *list, char *id, char *number, char *default_service)
{
	char 	*mnumber,
		*mservice;


	mnumber  = strdup_number(number);
	mservice = strdup_service(number);

	if (strcmp(mservice, "") == 0)
	{	list = add_item(list, id, default_service, mnumber);
	}
	else
	{	list = add_item(list, id, mservice, mnumber);
	}

	free(mnumber);
	free(mservice);

	return list;
}


/* -------------------------------------------------------------------- */
/* Expand a single name into SERVICE:NUMBER				*/
/* -------------------------------------------------------------------- */
static SMS_list *expandnumber(TOKEN_HEAP *global, TOKEN_HEAP *local, char *id, char *str, char *default_service)
{
	TOKEN_HEAP
		*heap;
	SMS_list
		*list = NULL,
		*sub_list;
	int i;
	char	*value;



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

	if (str[0] == '\0')
	{	return NULL;
	}


	lprintf(LOG_VERBOSE, "Expanding '%s'\n", str);

	if ((local != NULL) && ((heap = get_varlist(local, str)) != NULL))
	{	
		lprintf(LOG_VERBOSE, "Local: List '%s' found\n", str);

		i = 0;
		while ((value = get_strvalue_element(heap, i)) != NULL)
		{		
			sub_list = expandnumber(global, local, str, value, default_service);
			list     = insert_list(list, sub_list);

			i++;
		}
	}
	else
	if ((local != NULL) && ((value = get_strvalue(local, str)) != NULL))
	{
		lprintf(LOG_VERBOSE, "Local: Item '%s' found\n", str);
		list = add_number(list, str, value, default_service);
	}
	else
	if ((heap = get_varlist(global, str)) != NULL)
	{
		lprintf(LOG_VERBOSE, "Global: List '%s' found\n", str);

		i = 0;
		while ((value = get_strvalue_element(heap, i)) != NULL)
		{		
			sub_list = expandnumber(global, local, str, value, default_service);
			list     = insert_list(list, sub_list);

			i++;
		}
	}
	else
	if ((value = get_strvalue(global, str)) != NULL)
	{
		lprintf(LOG_VERBOSE, "Global: Item '%s' found\n", str);
		list = add_number(list, str, value, default_service);
	}
	else
	{	lprintf(LOG_VERBOSE, "Item '%s' NOT found\n", str);
		list = add_number(list, id, str, default_service);
	}

	return list;
}

/* -------------------------------------------------------------------- */
/* Expand a comma seperated list of names into SERVICE:NUMBER		*/
/* -------------------------------------------------------------------- */
SMS_list *SMS_expandnumber(TOKEN_HEAP *global, TOKEN_HEAP *local, char *id, char *str, char *default_service)
{
	char 	*ptr,
		*dst,
		buf[1024];
	SMS_list
		*list,
		*sub_list;


	list     = NULL;
	sub_list = NULL;


	dst = buf;
	ptr = str;
	while (*ptr != '\0')
	{
		if (*ptr == ',')
		{
			*dst = '\0';

			sub_list = expandnumber(global, local, id, buf, default_service);
			list     = insert_list(list, sub_list);

			dst = buf;
			ptr++;
		}
		else
		{	*dst = *ptr;

			dst++;
			ptr++;
		}
	}

	*dst = '\0';

	sub_list = expandnumber(global, local, id, buf, default_service);
	list     = insert_list(list, sub_list);


	return list;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int SMS_validate_expanded_numbers(SMS_list *numbers)
{
	DEVICE_ENTRY
		*device;

	char	*id,
		*service,
		*protocol;

	int	count;

	SMS_list
		*node;


	count = 0;
		
	node = get_first(numbers);
	while (node != NULL)
	{
		service  = get_service(node);
		protocol = get_protocol(service);
		if (protocol == NULL)
		{	lprintf(LOG_ERROR, "Service '%s' does not have a valid protocol entry\n", service);
			count++;
		}
		else
		{	device = get_device(protocol);
			if (device == NULL)
			{	lprintf(LOG_ERROR, "Driver for service %s NOT found\n", service);
				count++;
			}
			else
			{	id = get_number(node);

				if (!((*device->validate_id)(id)))
				{
					lprintf(LOG_WARNING, "Invalid id: %s\n", id);
					count++;
				}
			}	
		}

		node = get_next(node);
	}

	return count;
}

