/*---------------------------------------------------------------------------*\

	FILE....: utilfuncs.cpp
	AUTHOR..: Ben Kramer, Ron Lee
	DATE....: 26/07/2004
	DESC....: Contains a bunch of common utility functions


         Voicetronix Voice Processing Board (VPB) Software
         Copyright (C) 1999-2008 Voicetronix www.voicetronix.com.au

         This library is free software; you can redistribute it and/or
         modify it under the terms of the GNU Lesser General Public
         License as published by the Free Software Foundation; either
         version 2.1 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
         Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
         License along with this library; if not, write to the Free Software
         Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
         MA  02110-1301  USA

\*---------------------------------------------------------------------------*/

#include "vpbapi.h"
#include "utilfuncs.h"
#include "mess.h"

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>


/* Conf file reading states */
#define C_START		0
#define C_SECT		1
#define C_DATA 		2
#define C_SUBSECT	3
/* section types */
#define CS_NONE 	0
#define CS_GEN		1
#define CS_CARD 	2
#define CS_CHAN		3


// Helper function to get info from the driver proc exports
bool GetProcfsInfo(const char *node, char *buf, size_t size)
{ //{{{
	int fd = open(node, O_RDONLY);
	if( fd == -1 ){
		mprintf("could not open node '%s': %m\n", node);
		return false;
	}

	int n;
	switch( (n = read(fd,buf,size)) )
	{
	    case -1:
		mprintf("error reading '%s': %m\n", node);
	    case 0:
		close(fd);
		return false;

	    default:
		buf[n] = '\0';
		close(fd);
		return true;
	}
} //}}}

#if 0
bool SetProcfsInfo(const char *node, const char *value, size_t len);
{ //{{{
	int fd = open(node, O_WRONLY);
	if( fd == -1 ){
		mprintf("could not open node '%s': %m\n", node);
		return false;
	}

	int ret = write(fd, value, len);

	close(fd);

	if( ret == len ) return true;
	if( ret == -1 ) {
		mprintf("error writing '%s' to '%s': %m\n", value, node);
	} else
		mprintf("short write of '%s' to '%s' (%d): %m\n",
			value, node, ret);
	}
	return false;
} //}}}
#endif


static void conf_dump_print(CONF_INFO *conf_p)
{ //{{{
	int x,z;

	mprintf("=================== GENERAL ========================\n");
	mprintf("Country code [%d]\n",conf_p->country_code);
	mprintf("Tone count[%d]\n",conf_p->tone_count);
	if (conf_p->tone_count > 0){
		for(int i=0; i < conf_p->tone_count; ++i){
			mprintf("\t Tone [%d]:\n",i);
			mprintf("\t\t Defn [%s]\n",conf_p->tones[i].defn);
			mprintf("\t\t Type [%s]\n",conf_p->tones[i].type);
			mprintf("\t\t Freq1 [%d]\n",conf_p->tones[i].freq1);
			mprintf("\t\t Band1 [%d]\n",conf_p->tones[i].band1);
			mprintf("\t\t Time On [%d]\n",conf_p->tones[i].ton);
			mprintf("\t\t Time Off [%d]\n",conf_p->tones[i].toff);
			mprintf("\t\t Freq2 [%d]\n",conf_p->tones[i].freq2);
			mprintf("\t\t Band2 [%d]\n",conf_p->tones[i].band2);
			mprintf("\t\t snr [%d]\n",conf_p->tones[i].snr);
			mprintf("\t\t twist [%d]\n",conf_p->tones[i].twist);
		}
	}
	mprintf("Card Count[%d]\n",conf_p->cardcount);
	if (conf_p->cardcount > 0 ){
		for(unsigned int i=0; i < conf_p->cardcount && i < 254; ++i){
			mprintf("\tCard[%d] type[%d] number[%d]\n", i,
				conf_p->cards[i].type, conf_p->cards[i].number);
		}
	}
	mprintf("=================== OpenPRI ========================\n");
	mprintf("Channels [%d]\n",conf_p->OpenPri.channels);
	mprintf("Cards [%d]\n",conf_p->OpenPri.cards);
	for (x=0;x<conf_p->OpenPri.cards;x++){
		mprintf("\tCard Num [%d]\n",x);
		mprintf("\tInterface type [%d]\n",conf_p->OpenPri.card[x].if_type);
		mprintf("\tNode type [%d]\n",conf_p->OpenPri.card[x].node);
		mprintf("\tD-channel [%d]\n",conf_p->OpenPri.card[x].d_channel);
		z=(conf_p->OpenPri.card[x].if_type == VPB_PRI_E1?31:24);
		for(int i=1; i <= z; ++i){
			mprintf("\t Channel Num[%d]\n",i);
			mprintf("\t\t Channel [%d]\n",
				conf_p->OpenPri.card[x].iface[i].channel);
			mprintf("\t\t Channel Name [%s]\n",
				conf_p->OpenPri.card[x].iface[i].name);
			mprintf("\t\t Card Name [%s]\n",
				conf_p->OpenPri.card[x].iface[i].card);
			mprintf("\t\t Encoding [%s]\n",
				(VPB_ALAW == conf_p->OpenPri.card[x].iface[i].encoding
				    ? "alaw"
				    : (VPB_MULAW == conf_p->OpenPri.card[x].iface[i].encoding
					? "ulaw" : "raw")));
		}
	}
	mprintf("=================== OpenLine =======================\n");
	mprintf("Channels [%d]\n",conf_p->OpenLine.cards * 4);
	mprintf("Cards [%d]\n",conf_p->OpenLine.cards);
	for (x=0;x<conf_p->OpenLine.cards;x++){
		mprintf("\tCard Num [%d]\n",conf_p->OpenLine.card[x].cardnum);
		mprintf("\tCard type [%d]\n",conf_p->OpenLine.card[x].type);
		mprintf("\tCard channels [4]\n");
		for(int i=0; i < 4; ++i) {
			mprintf("\t\tChannel [%d]\n", i);
			mprintf("\t\tType [%d]\n", VPB_FXO);
			mprintf("\t\tSettings [%d]\n",
				conf_p->OpenLine.card[x].iface[i].settings);
			if (conf_p->OpenLine.card[x].iface[i].settings & MOD_HWPG){
				mprintf("\t\t\tHW Play Gain [%f]\n",
					conf_p->OpenLine.card[x].iface[i].hw_play_gain);
			}
			if (conf_p->OpenLine.card[x].iface[i].settings & MOD_HWRG){
				mprintf("\t\t\tHW Record Gain [%f]\n",
					conf_p->OpenLine.card[x].iface[i].hw_rec_gain);
			}
			if (conf_p->OpenLine.card[x].iface[i].settings & MOD_PG){
				mprintf("\t\t\tPlay Gain [%f]\n",
					conf_p->OpenLine.card[x].iface[i].play_gain);
			}
			if (conf_p->OpenLine.card[x].iface[i].settings & MOD_RG){
				mprintf("\t\t\tRecord Gain [%f]\n",
					conf_p->OpenLine.card[x].iface[i].rec_gain);
			}
			if (conf_p->OpenLine.card[x].iface[i].settings & MOD_BALS){
				mprintf("\t\t\tBal1[0x%x]\n",
					conf_p->OpenLine.card[x].iface[i].codec_hyb_bal1);
				mprintf("\t\t\tBal2[0x%x]\n",
					conf_p->OpenLine.card[x].iface[i].codec_hyb_bal2);
				mprintf("\t\t\tBal3[0x%x]\n",
					conf_p->OpenLine.card[x].iface[i].codec_hyb_bal3);
			}
		}
	}
} //}}}

llc_list *vpb_read_confll(CONF_INFO *cp)
{ //{{{
	char file[]="/etc/vpb/vpb.conf";
	char *tmp;
	int tmpi;
	char name[64];
	char confval[64];
	float hw_play_gain = 0.0;
	float hw_rec_gain  = 0.0;
	float play_gain    = 0.0;
	float rec_gain     = 0.0;
	int encoding=-1;

	cp->cardcount       = 0;

	llc_list *list      = NULL;
	llc_cat  *cat       = NULL;
	llc_var  *var       = NULL;
	llc_list *list_root = conf_load(file);

	if( ! list_root ) return NULL;

	mprintf("vpb_read_confll: loaded [%s]\n",file);

	list = conf_find_list(list_root,"general");
	if(list != NULL)
	{ //{{{
		cat = conf_find_cat(list->cats,"general");

		cp->verbosity    = atoi( conf_find_val(confval, cat, "verbosity") );
		cp->country_code = atoi( conf_find_val(confval, cat, "country") );

		cat = conf_find_cat(list->cats,"cards");
		var = cat->vars;
		while (var != NULL){
			int bdno   = atoi(var->name);	// board number
			int bdty   = -1;		// board type
			int bdtyno = -1;		// board type number
			if (strncasecmp(var->value,"openpci",7)==0){
				bdty=VPB_OPCI;
			}
			else if (strncasecmp(var->value,"openswi",7)==0){
				bdty=VPB_OSW;
			}
			else if (strncasecmp(var->value,"openpri",7)==0){
				bdty=VPB_PRI;
			}
			else if (strncasecmp(var->value,"openlin",7)==0){
				bdty=VPB_V4PCI;
			}
			else if (strncasecmp(var->value,"openlog",7)==0){
				bdty=VPB_V4LOG;
			}
			if (bdty != -1){
				tmp    = strstr(var->value,":");
				bdtyno = atoi(tmp+1);

				if((bdno > -1 && bdno < 254)
				&& (bdtyno > -1 && bdtyno < 30))
				{
					cp->cards[bdno].type=bdty;
					cp->cards[bdno].number=bdtyno;
				} else {
					mprintf("Invalid board number or "
						"board type number [%d][%d]\n",
						bdty,bdtyno);
				}
			} else {
				mprintf("Couldnt work out board type\n");
			}
			var = var->next;
		}
		cp->tone_count=0;
	} //}}}
	else {
		mprintf("vpb_read_confll: Couldnt find the 'general' section\n");
		conf_release_list( list_root );
		return NULL;
	}

	list = conf_find_list(list_root,"openline");

	// This is a kludge, to let you use either 'openline' or 'openlog'
	// Really we need to allow both together, but first we will need to
	// factor out all the code in the block below.
	if(list == NULL)
		list = conf_find_list(list_root,"openlog");

	if(list != NULL)
	{ //{{{
		mprintf("vpb_read_confll: Scanning OpenLine conf..\n");

		cat                = conf_find_cat(list->cats, "general");
		cp->OpenLine.cards = atoi( conf_find_val(confval, cat, "cards") );

		if(cp->OpenLine.cards > 0)
		{
			cp->cardcount += cp->OpenLine.cards;
			for(int i=0; i < cp->OpenLine.cards; ++i)
			{
				hw_play_gain=0;
				hw_rec_gain=0;
				play_gain=0;
				rec_gain=0;
				unsigned int bal1 = 0;
				unsigned int bal2 = 0;
				unsigned int bal3 = 0;
				int settings = 0;

				sprintf(name,"card%d",i);
				cat = conf_find_cat(list->cats,name);
				var = cat->vars;
				cp->OpenLine.card[i].type    = VPB_V4PCI;
				cp->OpenLine.card[i].cardnum = i;
				while (var != NULL){
					if (strcasecmp(var->name,"bal1")==0){
						//bal1 = (unsigned short)atoi(var->value);
						sscanf(var->value,"%x",&bal1);
						settings |= MOD_BALS;
					}
					else if (strcasecmp(var->name,"bal2")==0){
						//bal2 = (unsigned short)atoi(var->value);
						sscanf(var->value,"%x",&bal2);
						settings |= MOD_BALS;
					}
					else if (strcasecmp(var->name,"bal3")==0){
						//bal3 = (unsigned short)atoi(var->value);
						sscanf(var->value,"%x",&bal3);
						settings |= MOD_BALS;
					}
					else if (strcasecmp(var->name,"hwplaygain")==0){
						hw_play_gain = atof(var->value);
						settings |= MOD_HWPG;
					}
					else if (strcasecmp(var->name,"hwrecordgain")==0){
						hw_rec_gain = atof(var->value);
						settings |= MOD_HWRG;
					}
					else if (strcasecmp(var->name,"playgain")==0){
						play_gain = atof(var->value);
						settings |= MOD_PG;
					}
					else if (strcasecmp(var->name,"recordgain")==0){
						rec_gain = atof(var->value);
						settings |= MOD_RG;
					}
					else if (strcasecmp(var->name,"type")==0){
						if(strncasecmp(var->value,"openli",6) == 0){
							cp->OpenLine.card[i].type = VPB_V4PCI;
						}
						else if(strncasecmp(var->value,"openlo",6) == 0){
							cp->OpenLine.card[i].type = VPB_V4LOG;
						}
					}
					else if (strcasecmp(var->name,"chan")==0){
						int channel      = atoi(var->value);
						ANA_IFACE &iface =
							cp->OpenLine.card[i].iface[channel];

						iface.hw_play_gain = hw_play_gain;
						iface.hw_rec_gain  = hw_rec_gain;
						iface.play_gain    = play_gain;
						iface.rec_gain     = rec_gain;
						iface.codec_hyb_bal1 = bal1;
						iface.codec_hyb_bal2 = bal2;
						iface.codec_hyb_bal3 = bal3;
						iface.settings       = settings;
					}
					var = var->next;
				}
			}
		}
	} //}}}
	else {
		cp->OpenLine.cards=0;
	}

	/* Lets check out the OpenPri stuff */
	list = conf_find_list(list_root,"openpri");
	if(list != NULL) { //{{{
		mprintf("vpb_read_confll: Scanning OpenPri conf..\n");

		cat               = conf_find_cat(list->cats,"general");
		cp->OpenPri.cards = atoi( conf_find_val(confval, cat, "cards") );

		if(cp->OpenPri.cards > 0)
		{
			cp->cardcount       += cp->OpenPri.cards;
			cp->OpenPri.channels = atoi( conf_find_val(confval, cat, "channels") );

			for(int i=0; i < cp->OpenPri.cards; ++i)
			{
				int settings = 0;
				cp->OpenPri.card[i].node=ISDN_NODE_CLIENT;
				sprintf(name,"card%d",i);
				cat = conf_find_cat(list->cats,name);
				var = cat->vars;
				while (var != NULL){
                                        //XXX Remove these next two...
					if (strcasecmp(var->name,"hwplaygain")==0){
						hw_play_gain = atof(var->value);
						settings |= MOD_HWPG;
					}
					else if (strcasecmp(var->name,"hwrecordgain")==0){
						hw_rec_gain = atof(var->value);
						settings |= MOD_HWRG;
					}
					else if (strcasecmp(var->name,"playgain")==0){
						play_gain = atof(var->value);
						settings |= MOD_PG;
					}
					else if (strcasecmp(var->name,"recordgain")==0){
						rec_gain = atof(var->value);
						settings |= MOD_RG;
					}
					else if(strcasecmp(var->name,"name")==0){
						char *c = (char*)cp->OpenPri.card[i].name;

						strncpy(c, var->value, OPRI_NAME_LEN - 1);
						c[OPRI_NAME_LEN - 1] = '\0';
					}
					else if(strcasecmp(var->name,"iftype")==0){
						if (strcasecmp(var->value,"e1")==0){
							cp->OpenPri.card[i].if_type=VPB_PRI_E1;
						}
						else {
							cp->OpenPri.card[i].if_type=VPB_PRI_T1;
						}
					}
					else if(strcasecmp(var->name,"dchannel")==0){
						cp->OpenPri.card[i].d_channel=atoi(var->value);
					}
					else if(strcasecmp(var->name,"priverbose")==0){
						cp->OpenPri.card[i].priverbose=atoi(var->value);
					}
					else if(strcasecmp(var->name,"encoding")==0){
						if(strcasecmp(var->value,"ALAW")==0){
							encoding=VPB_ALAW;
						}
						else if(strcasecmp(var->value,"ULAW")==0){
							encoding=VPB_MULAW;
						}
						else if(strcasecmp(var->value,"MULAW")==0){
							encoding=VPB_MULAW;
						}
						else if(strcasecmp(var->value,"raw")==0){
							encoding=VPB_RAW;
						}
						//cp->OpenPri.card[i].encoding=tmpi;
					}
					else if(strcasecmp(var->name,"dialplan")==0){
						tmpi=ISDN_DP_UNKNOWN;
						if(strcasecmp(var->value,"national")==0){
							tmpi=ISDN_DP_NATIONAL_ISDN;
						}
						else if(strcasecmp(var->value,"international")==0){
							tmpi=ISDN_DP_INTERNATIONAL_ISDN;
						}
						else if(strcasecmp(var->value,"local")==0){
							tmpi=ISDN_DP_LOCAL_ISDN;
						}
						else if(strcasecmp(var->value,"private")==0){
							tmpi=ISDN_DP_PRIVATE;
						}
						cp->OpenPri.card[i].dialplan=tmpi;
					}
					else if(strcasecmp(var->name,"localdialplan")==0){
						tmpi=ISDN_DP_UNKNOWN;
						if(strcasecmp(var->value,"national")==0){
							tmpi=ISDN_DP_NATIONAL_ISDN;
						}
						else if(strcasecmp(var->value,"international")==0){
							tmpi=ISDN_DP_INTERNATIONAL_ISDN;
						}
						else if(strcasecmp(var->value,"local")==0){
							tmpi=ISDN_DP_LOCAL_ISDN;
						}
						else if(strcasecmp(var->value,"private")==0){
							tmpi=ISDN_DP_PRIVATE;
						}
						cp->OpenPri.card[i].localdialplan=tmpi;
					}
					else if(strcasecmp(var->name,"protocol")==0){
						if(strcasecmp(var->value,"NI2")==0){
							tmpi=ISDN_PROTO_NI2;
						}
						else if(strcasecmp(var->value,"DMS100")==0){
							tmpi=ISDN_PROTO_DMS100;
						}
						else if(strcasecmp(var->value,"LUCENT5E")==0){
							tmpi=ISDN_PROTO_LUCENT5E;
						}
						else if(strcasecmp(var->value,"ATT4ESS")==0){
							tmpi=ISDN_PROTO_ATT4ESS;
						}
						else if(strcasecmp(var->value,"EUROISDN_E1")==0){
							tmpi=ISDN_PROTO_EUROISDN_E1;
						}
						else if(strcasecmp(var->value,"EUROISDN_T1")==0){
							tmpi=ISDN_PROTO_EUROISDN_T1;
						}
						else if(strcasecmp(var->value,"NI1")==0){
							tmpi=ISDN_PROTO_NI1;
						}
						else if(strcasecmp(var->value,"GR303_EOC")==0){
							tmpi=ISDN_PROTO_GR303_EOC;
						}
						else if(strcasecmp(var->value,"GR303_TMC")==0){
							tmpi=ISDN_PROTO_GR303_TMC;
						}
						else
							tmpi=ISDN_PROTO_UNKNOWN;

						cp->OpenPri.card[i].protocol=tmpi;
					}
					else if(strcasecmp(var->name,"node")==0){
						if(strcasecmp(var->value,"network")==0){
							tmpi=ISDN_NODE_NETWORK;
						} else if(strcasecmp(var->value,"log")==0){
							tmpi=ISDN_NODE_LOG;
						} else {
							tmpi=ISDN_NODE_CLIENT;
						}
						cp->OpenPri.card[i].node=tmpi;
					}
					else if(strncasecmp(var->name,"channel",7)==0){
						tmp=strtok(var->name,"channel");
						tmpi=atoi(tmp);
						if( tmpi > 0 && tmpi < cp->OpenPri.channels + 2 ){
							cp->OpenPri.card[i].iface[tmpi].channel=tmpi;
							strcpy((char *)cp->OpenPri.card[i].iface[tmpi].name,
							       var->value);
							strcpy((char *)cp->OpenPri.card[i].iface[tmpi].card,
							       (char *)cp->OpenPri.card[i].name);
							cp->OpenPri.card[i].iface[tmpi].encoding =
								(encoding == -1) ? VPB_ALAW : encoding;
						} else
							mprintf("Invalid channel number %d\n", tmpi);
					}
				var = var->next;
				}
				cp->OpenPri.card[i].hw_play_gain = hw_play_gain;
				cp->OpenPri.card[i].hw_rec_gain = hw_rec_gain;
				cp->OpenPri.card[i].play_gain = play_gain;
				cp->OpenPri.card[i].rec_gain = rec_gain;
				cp->OpenPri.card[i].settings = settings;
			}
		}
	} //}}}
	else {
		cp->OpenPri.cards=0;
		cp->OpenPri.channels=0;
	}

	/* Lets check out the vtcore stuff */
	list = conf_find_list(list_root,"vtcore");
	if(list != NULL) { //{{{
		mprintf("vpb_read_confll: Scanning vtcore conf..\n");

		cat              = conf_find_cat(list->cats, "general");
		cp->vtcore.cards = atoi( conf_find_val(confval, cat, "cards") );

		if(cp->vtcore.cards > 0)
		{
			cp->vtcore.card = new VTCORE_CARD[cp->vtcore.cards];
			cp->cardcount  += cp->vtcore.cards;

			for(int i=0; i < cp->vtcore.cards; ++i)
			{
				sprintf(name,"card%d",i);
				mprintf("Looking for cat for [%s]\n",name);
				cat = conf_find_cat(list->cats,name);
				if(cat)
					var = cat->vars;
				cp->vtcore.card[i].cardnum=i;
				cp->vtcore.card[i].config=(void *)var;
				while (var != NULL){
				    if(strcasecmp(var->name,"type")==0) {
					if(strncasecmp(var->value,"openpci",7) == 0) {
						cp->vtcore.card[i].type=VPB_OPCI;
					}
					else if(strncasecmp(var->value,"openswitch",7) == 0) {
						cp->vtcore.card[i].type=VPB_OSW;
					}
				    }
				    var = var->next;
				}
				// most of the rest for vtcore cards are checked
				// in VTCore::Configure or playrec_open
			}
		}
	} //}}}
	else {
		cp->vtcore.cards=0;
	}
//	conf_dumper(cp);
	conf_dump_print(cp);

	return list_root;
} //}}}


//XXX Old and unused.
#if 0
//{{{

/* internal function defns */
static void trim_buffer(char * buffer);
static int conf_get_section(char * buffer);
static int conf_save_buf(int file_type, CONF_INFO * conf_pointer, int state,
			 int sect, int subsect, int cardno, char *buffer);
static int conf_get_tag_value(char * tag,char * value,char * buffer);
static int conf_get_cardno(char * buffer);


/******************************************************************************
	FUNC: vpb_read_conf
	DESC: Reads a conf file in to the conf_info structure pointer passed
	AUTH: Ben Kramer
	DATE: 26/07/2004
******************************************************************************/
int vpb_read_conf(CONF_INFO * conf_pointer, char * file_name, int file_type)
{
	FILE *conf_file;
	char buffer[128];
	char * buf_p;
	int state=C_START;
	int sect=0;
	int newsect=0;
	int subsect=0;
	int count=0;
	int ret=0;
	int cardno=0;

	/* Initialize some things */
	/*
	conf_pointer->tone_count=0;
	conf_pointer->OpenPri.cards=0;
	conf_pointer->OpenLine.cards=0;
	*/

	buf_p=buffer;

	conf_file = fopen(file_name,"r");
	if (conf_file == NULL){
		return -1;
	}
	else {
		while( count < 128 && fread(buf_p,sizeof(char),1,conf_file) !=0 ){
			count++;
			//mprintf("%c",*buf_p);
			if (*buf_p == 10){
				*buf_p='\0';
				trim_buffer(buffer);
//				mprintf("[%s]\n",buffer);
				if ((buffer[0] != '#')&&(buffer[0] != '\0')){
					/* we have a non-comment line */
					if (buffer[0] == '['){
						newsect=conf_get_section(buffer);
//						mprintf("SECTION[%d]\n",newsect);
						if(state !=C_SECT && state != C_SUBSECT){
							state=C_SECT;
							sect=newsect;
						}
						else if(state == C_SECT) {
							if(sect == CS_GEN || sect == CS_CARD){
								sect=newsect;
							}
							else {
								state=C_SUBSECT;
								sect=newsect;
							}
						}
						// Check if we are in a card section
						// and grab its number
						if (sect == CS_CARD){
							cardno=conf_get_cardno(buffer);
						}
					}
					else {
						if(state != C_SECT && state != C_SUBSECT){
							// DANGER we are not in a section
							// to store the info!
//							mprintf("Cant save info, not in section!\n");
						}
						else {
							ret = conf_save_buf(file_type,
									    conf_pointer,
									    state,
									    sect,
									    subsect,
									    cardno,
									    buffer);
							if(ret != 0){
//								mprintf("PROBLEM: Couldnt save info!!\n");
							}
						}
					}
				}
				count=0;
				buf_p=buffer;
			}
			else {
				buf_p++;
			}
		}
	}
	fclose(conf_file);
//	conf_dumper(conf_pointer);
	conf_dump_print(conf_pointer);
	return 0;
}

void trim_buffer(char *buffer)
{ //{{{
	char * buf_p=buffer;
	int start = 0;
	int finish = 0;
	int state = 0;
	int count = 0;

	if (*buf_p == '\0'){
		return;
	}
//	/* Find start */
	for(; *buf_p != '\0'; ++buf_p, ++count )
	{
		if( state == 0 && *buf_p > 32 && *buf_p < 127 )
		{
			start = count;
			state = 1;
//			mprintf("== found start of text at [%d][%c][%d]\n",
//				count,*buf_p,short(*buf_p));
		}
	}
//	/* find finish */
	state = 0;
	while(count > 0){
		--buf_p;
		--count;
		if( state == 0 && *buf_p > 32 && *buf_p < 127 ){
			finish = count;
			state = 1;
//			mprintf("== found finish of text at [%d][%c][%d]\n",
//				count,*buf_p,short(*buf_p));
		}
	}
	/* move from start to finish inside buffer */
	buf_p = buffer;
	for(int i = start; i <= finish; ++i){
		*buf_p = buffer[i];
		++buf_p;
	}
	*buf_p='\0';
} //}}}

int conf_get_section(char * buffer)
{
	char sectbuf[126];
	char * buf_p;
	char * sect_p;
	int count;
	buf_p=buffer;
	sect_p=sectbuf;
	buf_p++;
	count=0;
	while((count<126)&&(*buf_p != ']')){
		count++;
		*sect_p=*buf_p;
		sect_p++;
		buf_p++;
	}
	*(sect_p++)='\0';
	if(strncasecmp(sectbuf,"general",7)==0){
		return CS_GEN;
	}
	if(strncasecmp(sectbuf,"card",4)==0){
		return CS_CARD;
	}
	else {
		return CS_NONE;
	}
}

static int conf_get_cardno(char * buffer)
{
	char sectbuf[126];
	char * buf_p;
	char * sect_p;
	int count;
	int tmp;
	char * tmp_p;
	buf_p=buffer;
	sect_p=sectbuf;
	buf_p++;
	count=0;
	while((count<126)&&(*buf_p != ']')){
		count++;
		*sect_p=*buf_p;
		sect_p++;
		buf_p++;
	}
	*(sect_p++)='\0';
	if(strncasecmp(sectbuf,"card",4)==0){
		tmp_p=strtok(sectbuf,"card");
		tmp=atoi(tmp_p);
		return tmp;
	}
	else {
		return -1;
	}
}

int conf_save_buf(int file_type, CONF_INFO *conf_p, int state, int sect,
		  int subsect, int cardno, char *buffer)
{
	(void)subsect;

	char tag[64],value[64];
	int ret;
	int tmp;
	char * tmp_p;
	ret=conf_get_tag_value(tag,value,buffer);
//	mprintf("sect[%d] tag[%s] val[%s]\n",sect,tag,value);
	switch(state){
		case C_SECT:
			if ((sect == CS_GEN)&&(file_type == VPB_CONF_GEN)){
				if(strcasecmp(tag,"country")==0){
					conf_p->country_code=atoi(value);
					return 0;
				}
				if(strcasecmp(tag,"verbosity")==0){
					conf_p->verbosity=atoi(value);
					return 0;
				}
				if(strcasecmp(tag,"tone")==0){
					//XXX conf_save_tone(conf_p,value);
					// This should set up the tones[]
					// member I guess, but it is neither
					// specified not implemented at this
					// stage.  RL - 2006.
					return 0;
				}
			}
			else if ((sect == CS_GEN)&&(file_type == VPB_CONF_OP)){
				if(strcasecmp(tag,"channels")==0){
					conf_p->OpenPri.channels=atoi(value);
					return 0;
				}
				if(strcasecmp(tag,"cards")==0){
					conf_p->OpenPri.cards=atoi(value);
					return 0;
				}
			}
			else if ((sect == CS_GEN)&&(file_type == VPB_CONF_OL)){
				if(strcasecmp(tag,"cards")==0){
					conf_p->OpenLine.cards=atoi(value);
					return 0;
				}
			}
			else if ((sect == CS_CARD)&&(file_type == VPB_CONF_GEN)){
				int bdno = atoi(tag);	// board number
				int bdty=-1;		// board type
				int bdtyno=-1;		// board type number
				if (strncasecmp(value,"openpri",7)==0){
					bdty=VPB_CONF_OP;
				}
				else if (strncasecmp(value,"openlin",7)==0){
					bdty=VPB_CONF_OL;
				}
				if (bdty != -1){
					tmp_p=strstr(value,":");
					bdtyno=atoi(tmp_p+1);
					if((bdno > -1 && bdno < 254)
					&& (bdtyno > 0 && bdtyno < 30))
					{
						conf_p->cards[bdno].type=bdty;
						conf_p->cards[bdno].number=bdtyno;
						return 0;
					}
					else {
						mprintf("Invalid board number or board type number!\n");
					}
				}
				else {
					mprintf("Couldnt work out board type!\n");
				}
				return -1;
			}
			else if ((sect == CS_CARD)&&(file_type == VPB_CONF_OP)){
				if(strcasecmp(tag,"name")==0){
					strcpy((char *)conf_p->OpenPri.card[cardno].name,value);
					return 0;
				}
				else if(strcasecmp(tag,"iftype")==0){
					if (strcasecmp(value,"e1")==0){
						conf_p->OpenPri.card[cardno].if_type=VPB_PRI_E1;
					}
					else {
						conf_p->OpenPri.card[cardno].if_type=VPB_PRI_T1;
					}
					return 0;
				}
				else if(strcasecmp(tag,"dchannel")==0){
					conf_p->OpenPri.card[cardno].d_channel=atoi(value);
					return 0;
				}
				else if(strcasecmp(tag,"priverbose")==0){
					conf_p->OpenPri.card[cardno].priverbose=atoi(value);
					return 0;
				}
				else if(strcasecmp(tag,"encoding")==0){
					tmp=VPB_ALAW;
					if(strcasecmp(value,"ALAW")==0){
						tmp=VPB_ALAW;
					}
					else if(strcasecmp(value,"ULAW")==0){
						tmp=VPB_MULAW;
					}
					else if(strcasecmp(value,"MULAW")==0){
						tmp=VPB_MULAW;
					}
					//conf_p->OpenPri.card[cardno].encoding=tmp;
					return 0;
				}
				else if(strcasecmp(tag,"protocol")==0){
					if(strcasecmp(value,"NI2")==0){
						tmp=ISDN_PROTO_NI2;
					}
					else if(strcasecmp(value,"DMS100")==0){
						tmp=ISDN_PROTO_DMS100;
					}
					else if(strcasecmp(value,"LUCENT5E")==0){
						tmp=ISDN_PROTO_LUCENT5E;
					}
					else if(strcasecmp(value,"ATT4ESS")==0){
						tmp=ISDN_PROTO_ATT4ESS;
					}
					else if(strcasecmp(value,"EUROISDN_E1")==0){
						tmp=ISDN_PROTO_EUROISDN_E1;
					}
					else if(strcasecmp(value,"EUROISDN_T1")==0){
						tmp=ISDN_PROTO_EUROISDN_T1;
					}
					else if(strcasecmp(value,"NI1")==0){
						tmp=ISDN_PROTO_NI1;
					}
					else if(strcasecmp(value,"GR303_EOC")==0){
						tmp=ISDN_PROTO_GR303_EOC;
					}
					else if(strcasecmp(value,"GR303_TMC")==0){
						tmp=ISDN_PROTO_GR303_TMC;
					}
					else
						tmp=ISDN_PROTO_UNKNOWN;

					conf_p->OpenPri.card[cardno].protocol=tmp;
					return 0;
				}
				else if(strcasecmp(tag,"node")==0){
					if(strcasecmp(value,"network")==0){
						tmp=ISDN_NODE_NETWORK;
					} else if(strcasecmp(value,"log")==0){
						tmp=ISDN_NODE_LOG;
					} else {
						tmp=ISDN_NODE_CLIENT;
					}
					conf_p->OpenPri.card[cardno].node=tmp;
					return 0;
				}
				else if(strncasecmp(tag,"channel",7)==0){
//					mprintf("\t\t\tTAG=>[%s]\n",tag);
					tmp_p=strtok(tag,"channel");
//					mprintf("\t\t\ttmp_p=>[%s]\n",tmp_p);
					tmp=atoi(tmp_p);
//					mprintf("\t\t\ttmp=>[%d]\n",tmp);
//					mprintf("\t\t\tvalue=>[%s]\n",value);
					conf_p->OpenPri.card[cardno].iface[tmp].channel=tmp;
					strcpy((char *)conf_p->OpenPri.card[cardno].iface[tmp].name,
					       value);
					strcpy((char *)conf_p->OpenPri.card[cardno].iface[tmp].card,
					       (char *)conf_p->OpenPri.card[cardno].name);
//					mprintf("\t\tName=>[%s]\n",conf_p->OpenPri.iface[tmp].name);
					return 0;
				}
			}
		break;

		case C_SUBSECT:
		break;
	}
	return -1;
}

int conf_get_tag_value(char * tag,char * value,char * buffer)
{
	int got_tag=0;
	char * buf_p=buffer;
	char * tag_p=tag;
	char * val_p=value;
	while(*buf_p != '\0'){
		if (*buf_p == '='){
			got_tag=1;
		}
		else {
			if(!got_tag){
				*tag_p=*buf_p;
				tag_p++;
			}
			else {
				*val_p=*buf_p;
				val_p++;
			}
		}
		buf_p++;
	}
	if(!got_tag){
		*tag='\0';
		*value='\0';
		return -1;
	}
	else {
		*tag_p='\0';
		*val_p='\0';
		return 0;
	}
}

//}}}
#endif

#if 0
void conf_dumper(CONF_INFO * conf_p)
{
	int file;
	int size;
	file = open("conf_dump",O_CREAT|O_WRONLY|O_TRUNC);
	size = write(file,conf_p,sizeof(CONF_INFO));
	close(file);
	mprintf("Wrote to conf_dump [%d]\n",size);
	return;
}
#endif

