/* $Id: isdnconf.c,v 1.12 1998/09/22 20:59:08 luethje Exp $
 *
 * ISDN accounting for isdn4linux. (Report-module)
 *
 * Copyright 1996, 1997 by Stefan Luethje (luethje@sl-gw.lake.de)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Log: isdnconf.c,v $
 * Revision 1.12  1998/09/22 20:59:08  luethje
 * isdnrep:  -fixed wrong provider report
 *           -fixed wrong html output for provider report
 *           -fixed strange html output
 * kisdnlog: -fixed "1001 message window" bug ;-)
 *
 * Revision 1.11  1998/05/11 19:43:43  luethje
 * Some changes for "vorwahlen.dat"
 *
 * Revision 1.10  1998/05/10 22:11:52  luethje
 * Added support for VORWAHLEN2.EXE
 *
 * Revision 1.9  1997/05/25 19:40:53  luethje
 * isdnlog:  close all files and open again after kill -HUP
 * isdnrep:  support vbox version 2.0
 * isdnconf: changes by Roderich Schupp <roderich@syntec.m.EUnet.de>
 * conffile: ignore spaces at the end of a line
 *
 * Revision 1.8  1997/05/05 21:21:42  luethje
 * bugfix for option -M
 *
 * Revision 1.6  1997/04/15 00:20:01  luethje
 * replace variables: some bugfixes, README comleted
 *
 * Revision 1.5  1997/04/10 23:32:15  luethje
 * Added the feature, that environment variables are allowed in the config files.
 *
 * Revision 1.4  1997/04/06 21:06:08  luethje
 * problem with empty/not existing file resolved.
 *
 * Revision 1.3  1997/04/03 22:36:23  luethje
 * splitt the file isdn.conf into callerid.conf and ~/.isdn (for editing).
 *
 * Revision 1.2  1997/03/23 20:58:31  luethje
 * some bugfixes
 *
 */

#include "isdnconf.h"

/*****************************************************************************/

int print_in_modules(const char *fmt, ...);
int print_msg(int Level, const char *fmt, ...);
int add_data(section **conf_dat);
int delete_data(char *, char *, section **conf_dat);
int look_data(section **conf_dat);
int find_data(char *_alias, char *_number, section *conf_dat);
const char* make_word(const char *in);
char* tmp_dup(const char *in);
int add_line(section **Ptr, const char *Name);

/*****************************************************************************/

static int and    = 0;
static int add    = 0;
static int del    = 0;
static int msn    = 0;
static int quiet  = 0;
static int short_out= 0;
static int long_out= 0;
static int oneentry= 0;
static int isdnmon = 0;

static int match_flags = F_NO_HOLE_WORD;

static char areacode[SHORT_STRING_SIZE] = "";
static char si[SHORT_STRING_SIZE];
static char number[BUFSIZ] = "";
static char alias[BUFSIZ] = "";
static char conffile[BUFSIZ];
static char callerfile[BUFSIZ];

/*****************************************************************************/

int add_line(section **Ptr, const char *Name)
{
	char buf[BUFSIZ] = "";


	if (fgets(buf,BUFSIZ,stdin) != NULL)
	{
		if (strlen(buf) > 1)
		{
			buf[strlen(buf)-1] = '\0';

			if (Set_Entry(*Ptr,NULL,tmp_dup(Name),buf,C_WARN) == NULL)
			{
				print_msg(PRT_ERR,"%s\n","Can not allocate memory!");
				return -1;
			}
		}
	}
	else
	{
		free_section(*Ptr);
		*Ptr = NULL;
		return -1;
	}

	return 0;
}

/*****************************************************************************/

int add_data(section **conf_dat)
{
	int Cnt = 0;
	section *NewPtr = NULL;
	section *SubPtr = NULL;


	while(1)
	{
		NewPtr = NULL;

		if (Set_Section(&NewPtr,tmp_dup(msn?CONF_SEC_MSN:CONF_SEC_NUM),C_NOT_UNIQUE) == NULL)
		{
			print_msg(PRT_ERR,"%s\n","Can not allocate memory!");
			return -1;
		}

		if (!quiet)
			print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_ALIAS));
		if (add_line(&NewPtr,CONF_ENT_ALIAS))
			break;

		if (!quiet)
			print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_NUM));
		if (add_line(&NewPtr,CONF_ENT_NUM))
			break;

		if (!quiet)
			print_msg(PRT_NORMAL,"%s:\t\t",CONF_ENT_SI);
		if (add_line(&NewPtr,CONF_ENT_SI))
			break;

		if (!quiet)
			print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_ZONE));
		if (add_line(&NewPtr,CONF_ENT_ZONE))
			break;

		if (!quiet)
			print_msg(PRT_NORMAL,"%s:\t",make_word(CONF_ENT_INTFAC));
		if (add_line(&NewPtr,CONF_ENT_INTFAC))
			break;

		while(1)
		{
			SubPtr = NULL;

			if (Set_Section(&SubPtr,tmp_dup(CONF_SEC_FLAG),C_NOT_UNIQUE) == NULL)
			{
				print_msg(PRT_ERR,"%s\n","Can not allocate memory!");
				return -1;
			}

			if (!quiet)
				print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_FLAGS));
			if (add_line(&SubPtr,CONF_ENT_FLAGS))
				break;

			if (!quiet)
				print_msg(PRT_NORMAL,"%s:\t",make_word(CONF_ENT_PROG));
			if (add_line(&SubPtr,CONF_ENT_PROG))
				break;

			if (!quiet)
				print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_USER));
			if (add_line(&SubPtr,CONF_ENT_USER))
				break;

			if (!quiet)
				print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_GROUP));
			if (add_line(&SubPtr,CONF_ENT_GROUP))
				break;

			if (!quiet)
				print_msg(PRT_NORMAL,"%s:\t",make_word(CONF_ENT_INTVAL));
			if (add_line(&SubPtr,CONF_ENT_INTVAL))
				break;

			if (!quiet)
				print_msg(PRT_NORMAL,"%s:\t\t",make_word(CONF_ENT_TIME));
			if (add_line(&SubPtr,CONF_ENT_TIME))
				break;

			Set_SubSection(NewPtr,tmp_dup(CONF_ENT_START),SubPtr,C_APPEND | C_WARN);
		}

		if (!quiet)
			print_msg(PRT_NORMAL,"\n\n");

		while(*conf_dat != NULL)
			conf_dat = &((*conf_dat)->next);

		*conf_dat = NewPtr;
		Cnt++;
	}

	if (!quiet)
		print_msg(PRT_NORMAL,"\n");

	return Cnt;
}

/*****************************************************************************/

int delete_data(char * _alias , char * _number, section **conf_dat)
{
	short_out = 1;

	if (!quiet)
		print_msg(PRT_NORMAL,"Following entry deleted!\n");

	if (!quiet)
		find_data(_alias,_number,*conf_dat);

	Del_Section(conf_dat,NULL);
	return 0;
}

/*****************************************************************************/

int find_data(char *_alias, char *_number, section *conf_dat)
{
	auto char *ptr;
	auto entry *CEPtr;
	auto section *SPtr;
	const char *area;

	if (quiet)
	{
		print_msg(PRT_NORMAL,"%s",_alias?_alias:(number[0]?expand_number(number):alias));
	}
	else
	{
		print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_ALIAS),_alias?_alias:S_UNKNOWN);
		print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_NUM),_number?_number:S_UNKNOWN);

		if (_number != NULL && (ptr = get_areacode(_number,NULL,C_NO_ERROR)) != NULL)
			print_msg(PRT_NORMAL,"Location:\t%s\n",ptr);

		if (!short_out)
		{
			ptr = (CEPtr = Get_Entry(conf_dat->entries,CONF_ENT_SI))?(CEPtr->value?CEPtr->value:"0"):"0";
			print_msg(PRT_NORMAL,"%s:\t\t%s\n",CONF_ENT_SI,ptr);

			area = area_diff_string(NULL,_number);
			ptr = (char*)(const char*) (area[0] != '\0'?area:(CEPtr = Get_Entry(conf_dat->entries,CONF_ENT_ZONE))?(CEPtr->value?CEPtr->value:""):"");
			print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_ZONE),ptr);

			ptr = (CEPtr = Get_Entry(conf_dat->entries,CONF_ENT_INTFAC))?(CEPtr->value?CEPtr->value:""):"";
			print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_INTFAC),ptr);
		}

		if (long_out)
		{
			SPtr = Get_SubSection(conf_dat,CONF_ENT_START);

			while (SPtr != NULL)
			{
				ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_FLAGS))?(CEPtr->value?CEPtr->value:""):"";
				print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_FLAGS),ptr);

				ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_PROG))?(CEPtr->value?CEPtr->value:""):"";
				print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_PROG),ptr);
	
				ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_USER))?(CEPtr->value?CEPtr->value:""):"";
				print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_USER),ptr);

				ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_GROUP))?(CEPtr->value?CEPtr->value:""):"";
				print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_GROUP),ptr);

				ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_INTVAL))?(CEPtr->value?CEPtr->value:""):"";
				print_msg(PRT_NORMAL,"%s:\t%s\n",make_word(CONF_ENT_INTVAL),ptr);

				ptr = (CEPtr = Get_Entry(SPtr->entries,CONF_ENT_TIME))?(CEPtr->value?CEPtr->value:""):"";
				print_msg(PRT_NORMAL,"%s:\t\t%s\n",make_word(CONF_ENT_TIME),ptr);

				SPtr = SPtr->next;
			}
		}
	}

	print_msg(PRT_NORMAL,"\n");

	return 0;
}

/*****************************************************************************/

int look_data(section **conf_dat)
{
	int Cnt = 0;
	auto entry *CEPtr;
	char *_number = NULL, *_alias = NULL;
	char _si[SHORT_STRING_SIZE];
	section *old_conf_dat = NULL;


	while (*conf_dat != NULL)
	{
		old_conf_dat = *conf_dat;

		if (!strcmp((*conf_dat)->name,CONF_SEC_NUM) || !strcmp((*conf_dat)->name,CONF_SEC_MSN))
		{
			int Ret = 0;

			free(_number);
			free(_alias);
			_number = _alias = NULL;
			_si[0] = '\0';

			if ((CEPtr = Get_Entry((*conf_dat)->entries,CONF_ENT_NUM)) != NULL)
				if (del)
					_number = strdup(Replace_Variable(CEPtr->value));
				else
					_number = strdup(CEPtr->value);

			if ((CEPtr = Get_Entry((*conf_dat)->entries,CONF_ENT_ALIAS)) != NULL)
				if (del)
					_alias = strdup(Replace_Variable(CEPtr->value));
				else
					_alias = strdup(CEPtr->value);

			if ((CEPtr = Get_Entry((*conf_dat)->entries,CONF_ENT_SI)) != NULL &&
			    CEPtr->value != NULL)
				if (del)
					sprintf(_si,"%ld",strtol(Replace_Variable(CEPtr->value), NIL, 0));
				else
					sprintf(_si,"%ld",strtol(CEPtr->value, NIL, 0));

			if (and)
				Ret = 1;
			else
				Ret = 0;

			if (number[0] && _number != NULL)
			{
				if (!num_match(_number,number))
					Ret = 1;
				else
					Ret = 0;
			}

			if (alias[0] && _alias != NULL)
			{
				int Ret2 = 0;

				if (!match(alias,_alias,match_flags))
					Ret2 = 1;

				if (and)
					Ret &= Ret2;
				else
					Ret |= Ret2;
			}

			if (si[0])
			{
				int Ret2 = 0;

				if (*_si == '\0' || !strcmp(_si,si))
					Ret2 = 1;

				if (and)
					Ret &= Ret2;
				else
					Ret |= Ret2;
			}

			if (Ret == 1)
			{
				if (del)
				{
					delete_data(_alias,_number,conf_dat);
					Cnt++;
				}
				else
				{
					find_data(_alias,_number,*conf_dat);
					Cnt++;
				}

				if (oneentry)
					break;
			}
		}

		if (*conf_dat != NULL && old_conf_dat == *conf_dat)
			conf_dat = &((*conf_dat)->next);
	}

	if (Cnt == 0 && quiet && !del)
		find_data(NULL,_number,*conf_dat);

	free(_number);
	free(_alias);
	return Cnt;
}

/*****************************************************************************/

char* tmp_dup(const char *in)
{
	static char out[SHORT_STRING_SIZE];

	strcpy(out,in);
	return out;
}

/*****************************************************************************/

const char* make_word(const char *in)
{
	int i = 0;
	static char out[SHORT_STRING_SIZE];

	out[0] ='\0';

	while(in[i] != '\0')
		out[i] = tolower(in[i]),i++;

	out[i] ='\0';
	out[0] = toupper(out[0]);

	return out;
}

/*****************************************************************************/

int print_msg(int Level, const char *fmt, ...)
{
	auto va_list ap;
	auto char    String[LONG_STRING_SIZE];


	va_start(ap, fmt);
	vsnprintf(String, LONG_STRING_SIZE, fmt, ap);
	va_end(ap);

	if (Level & PRT_ERR)
		fprintf(stderr, "%s", String);
	else
		fprintf(stdout, "%s", String);

	return 0;
}

/*****************************************************************************/

int print_in_modules(const char *fmt, ...)
{
	auto va_list ap;
	auto char    String[LONG_STRING_SIZE];


	va_start(ap, fmt);
	(void)vsnprintf(String, LONG_STRING_SIZE, fmt, ap);
	va_end(ap);

	return print_msg(PRT_ERR, "%s", String);
}

/*****************************************************************************/

int main(int argc, char *argv[], char *envp[])
{
	int c;
	int Cnt = 0;
	section *conf_dat = NULL;
	char *myname = basename(argv[0]);
	FILE *fp;

	static char usage[]   = "%s: usage: %s [ -%s ]\n";
	static char options[] = "ADdn:a:t:f:c:wslimqgV1M:";


	set_print_fct_for_tools(print_in_modules);

	alias[0] = '\0';
	number[0] = '\0';
	sprintf(conffile,"%s%c%s",confdir(),C_SLASH,CONFFILE);
	strcpy(callerfile,USERCONFFILE);

	while ((c = getopt(argc, argv, options)) != EOF)
		switch (c) {
			case 'A' : add++;
			           break;

			case 'D' : del++;
			           match_flags &= ~F_NO_HOLE_WORD;
			           break;

 			case 'V' : print_version(myname);
			           exit(0);

			case 'd' : and++;
			           break;

			case 'm' : msn++;
			           break;

			case 'i' : match_flags |= F_IGNORE_CASE;
			           break;

			case 'n' : strcpy(number, optarg);
			           break;

			case 'a' : strcpy(alias, optarg);
			           break;

			case 't' : sprintf(si,"%ld",strtol(optarg, NIL, 0));
			           break;

			case 's' : short_out++;
			           break;

			case 'l' : long_out++;
			           break;

			case 'w' : match_flags &= ~F_NO_HOLE_WORD;
			           break;

			case 'M' : isdnmon++;
			           oneentry++;
			           and++;
			           quiet++;
			           strcpy(areacode, optarg);
			           strcpy(number, optarg);
			           break;

			case '1' : oneentry++;
			           break;

			case 'q' : quiet++;
			           break;

			case 'f' : strcpy(callerfile, optarg);
			           break;

			case 'c' : strcpy(areacode, optarg);
			           break;

			case 'g' : sprintf(callerfile,"%s%c%s",confdir(),C_SLASH,CALLERIDFILE);
			           break;

			case '?' : print_msg(PRT_ERR, usage, myname, myname, options);
			           return(1);
    }

	if (isdnmon && (add || del || short_out || long_out))
	{
		print_msg(PRT_ERR,"Error: Can not do isdnmon output and delete or add or short or long!\n",conffile);
		exit(7);
	}

	if (add || del)
	{
		if ((conf_dat = read_file(NULL, conffile, C_NOT_UNIQUE)) == NULL)
		{
			print_msg(PRT_ERR,"Error while reading file `%s': no rights on file, syntax error\nor emtpy (delete it first)!\n",conffile);
			exit(2);
		}

		if (Set_Codes(conf_dat) != 0)
		{
			print_msg(PRT_ERR,"Error: Variables `%s' and `%s' are not set!\n",CONF_ENT_AREA,CONF_ENT_COUNTRY);
			exit(5);
		}

		free_section(conf_dat);
		conf_dat = NULL;

		if (access(expand_file(callerfile),W_OK))
		{
			if (errno != ENOENT)
			{
				print_msg(PRT_ERR,"Error: Can not open file `%s' (%s)!\n",expand_file(callerfile),strerror(errno));
				exit(6);
			}
			else
			{
				if (add)
				{
					if ((fp = fopen(expand_file(callerfile),"w")) == NULL)
					{
						print_msg(PRT_ERR,"Error: Can not open file `%s' (%s)!\n",expand_file(callerfile),strerror(errno));
						exit(6);
					}
					else
						print_msg(PRT_ERR,"Create file `%s'!\n",expand_file(callerfile),strerror(errno));

					fclose(fp);
				}
				else
				{
					print_msg(PRT_ERR,"File `%s' doesn't exist!\n",expand_file(callerfile));
					exit(6);
				}
			}
		}
		else
		{
			if ((conf_dat = read_file(NULL, expand_file(callerfile), C_NOT_UNIQUE)) == NULL)
			{
				print_msg(PRT_ERR,"Error while reading file `%s': no rights on file, syntax error\nor emtpy (delete it first)!\n",expand_file(callerfile));
				exit(2);
			}
		}
	}
	else
	{
		if (read_isdnconf(&conf_dat) == NULL)
			exit(2);
	}

	if (number[0] != '\0')
	{
		strcpy(number, expand_number(number));
		if (isdnmon)
			print_msg(PRT_NORMAL,"%s\t",number);
	}

	if (areacode[0] != '\0')
	{
		char *ptr;
		int len;
		
		if ((ptr = get_areacode(areacode,&len,quiet?C_NO_ERROR|C_NO_WARN:0)) != NULL)
		{
			if (!isdnmon)
			{
				const char *area = area_diff_string(NULL,areacode);

				print_msg(PRT_NORMAL,"%s%s%s\n",ptr,area[0] != '\0'?" / ":"", area[0] != '\0'?area:"");
				exit(0);
			}
			
			print_msg(PRT_NORMAL,"%s\t%d\t",ptr,len);
		}
		else
		{
			if (!isdnmon)
				exit(3);

			print_msg(PRT_NORMAL,"\t0\t");
		}
	}

	if (optind < argc && !add)
	{
		if (!alias[0] && optind + 1 == argc)
			strcpy(alias, argv[optind]);
		else
		{
			print_msg(PRT_ERR,"Error: Can not set two strings for alias!\n");
			exit(3);
		}
	}

	if (!add)
	{
		if (!alias[0] && !number[0] && !si[0])
		{
			print_msg(PRT_ERR, usage, argv[0], argv[0], options);
			exit(4);
		}
	}
	else
	{
		if (alias[0] || number[0] || si[0])
		{
			print_msg(PRT_ERR, usage, argv[0], argv[0], options);
			exit(5);
		}
	}

	if (add && del)
	{
		print_msg(PRT_ERR,"Error: Can not do add and delete together!\n");
		exit(1);
	}

	if (short_out && long_out)
	{
		print_msg(PRT_ERR,"Error: Can not do long and short output together!\n");
		exit(1);
	}

	if (!add && !del && Replace_Variables(conf_dat))
		exit(8);

	if (add)
		Cnt = add_data(&conf_dat);
	else
		Cnt = look_data(&conf_dat);

	if ((add || del) && Cnt > 0)
	{
		if (conf_dat == NULL)
		{
			if (unlink(expand_file(callerfile)))
				print_msg(PRT_ERR,"Error: Can not delete file `%s' (%s)!\n",expand_file(callerfile),strerror(errno));
			else
				print_msg(PRT_ERR,"Warning: File `%s' is empty. It is deleted now!\n", expand_file(callerfile));
		}
		else
		if (write_file(conf_dat,expand_file(callerfile),myname,VERSION) == NULL)
			exit(5);
	}

	if (del && !Cnt)
		print_msg(PRT_ERR, "Warning: No entry deleted!\n");

	free_section(conf_dat);

	return 0;
}

