/*
 * Gnophone: A client for the Asterisk PBX
 *
 * Copyright (C) 2000-2005, Digium, Inc.
 *
 * Written by Mark Spencer
 *
 * Linux/UNIX version distributed under the terms of
 * the GNU General Public License
 *
 * telco.c: Number complete manipulation, etc.
 *
 */
#ifndef _TELCO_C_
#define _TELCO_C_
#endif
#include "gnophone.h"

#define IAX_DEFAULT_PORTNO 4569

static char iax_server[80];
static char iax_context[80];
static char iax_username[80];
static char iax_password[80];
static char iax_peer[80];
static char iax_secret[80];
static char iax_prefix[20];
static short iax_port = IAX_DEFAULT_PORTNO;
static int telco_mode;

static struct nbr_complete {
	char pattern[80];
	struct nbr_complete *next;
} *nlist;

void telco_clear_nbrc(void)
{
	struct nbr_complete *next, *cur;
	cur = nlist;
	while(cur) {
		next = cur->next;
		free(cur);
		cur = next;
	}
	nlist = NULL;
}

void telco_register_nbrc(char *s)
{
	struct nbr_complete *nbr;
	nbr = malloc(sizeof(struct nbr_complete));
	if (nbr) {
		strncpy(nbr->pattern, s, sizeof(nbr->pattern)-1);
		nbr->next = nlist;
		nlist = nbr;
	}
}

char *telco_to_irl(char *number)
{
	static char teluri[256];
	teluri[0] = '\0';
	if (!strlen(iax_server)) {
		snprintf(teluri + 1, sizeof(teluri) - 1, "IAX server not specified");
		return teluri;
	}

	if (strlen(iax_context)) {
		if (strlen(iax_username)) 
			snprintf(teluri, sizeof(teluri), "%s:%s@%s/%s", 
					iax_username, iax_password, iax_server, number);
		else
			snprintf(teluri, sizeof(teluri), "%s:%d/%s%s@%s", 
					iax_server, iax_port, iax_prefix, number, iax_context);
	} else {
		if (strlen(iax_username)) 
			snprintf(teluri, sizeof(teluri), "%s@%s:%d/%s%s", 
					iax_username, iax_server, iax_port, iax_prefix, number);
		else
			snprintf(teluri, sizeof(teluri), "%s:%d/%s%s", 
					iax_server, iax_port, iax_prefix, number);
	}
	return teluri;
}

char *telco_get_server()
{
	return iax_server;
}

char *telco_get_context()
{
	return iax_context;
}

char *telco_get_username()
{
	return iax_username;
}

char *telco_get_password()
{
	return iax_password;
}

char *telco_get_peer()
{
	return iax_peer;
}

char *telco_get_secret()
{
	return iax_secret;
}

char *telco_get_prefix()
{
	return iax_prefix;
}

short telco_get_port()
{
	return iax_port;
}

void telco_set_server(const gchar *server)
{
	strncpy(iax_server, server, sizeof(iax_server)-1);
}

void telco_set_context(const gchar *context)
{
	strncpy(iax_context, context, sizeof(iax_context)-1);
}

void telco_set_username(const gchar *username)
{
	strncpy(iax_username, username, sizeof(iax_username)-1);
}

void telco_set_password(const gchar *password)
{
	strncpy(iax_password, password, sizeof(iax_password)-1);
}

void telco_set_prefix(const gchar *prefix)
{
	strncpy(iax_prefix, prefix, sizeof(iax_prefix)-1);
}

void telco_set_port(short port)
{
	iax_port = port;
}

void telco_set_peer(const gchar *peer)
{
	strncpy(iax_peer, peer, sizeof(iax_peer)-1);
}

void telco_set_secret(const gchar *secret)
{
	strncpy(iax_secret, secret, sizeof(iax_secret)-1);
}

void telco_set_mode(int mode)
{
	telco_mode = mode;
}

int telco_get_mode(void)
{
	return telco_mode;
}

static char *telco_config_file(void)
{
	static char fn[256];
	if (getenv("HOME")) {
		snprintf(fn, sizeof(fn), "%s/.gnophone/telco.cfg", getenv("HOME"));
		return fn;
	} else
		return NULL;
}

void telco_iterate(void (*func)(char *s, void *data), void *data)
{
	struct nbr_complete *n;
	n = nlist;
	while(n) {
		func(n->pattern, data);
		n = n->next;
	}
}

int telco_save_settings(void)
{
	FILE *f;
	char *fn;
	struct nbr_complete *n;
	fn = telco_config_file();
	if (fn) {
		f = fopen(fn, "w");
		if (f) {
			fprintf(f, 
"\
#\n\
# Automatically generated by gnophone\n\
#\n\
mode=%d\n\
iaxserver=%s\n\
iaxcontext=%s\n\
iaxusername=%s\n\
iaxpassword=%s\n\
iaxpeer=%s\n\
iaxsecret=%s\n\
iaxprefix=%s\n\
iaxport=%d\n\
",
			telco_mode, iax_server, iax_context, iax_username, iax_password, iax_peer, iax_secret,
			iax_prefix, iax_port);
			n = nlist;
			while(n) {
				fprintf(f, "nbrcomplete=%s\n", n->pattern);
				n = n->next;
			}
			fclose(f);
		} else
			return -1;
	} else
		return -1;
	return 0;
}

static int load_settings_from_file(void)
{
	FILE *f;
	char *fn;
	char buf[80];
	char *var, *value;
	
	telco_clear_nbrc();
	if ((fn = telco_config_file())) {
		f = fopen(fn, "r");
		if (f) {
			while(!feof(f)) {
				fgets(buf, sizeof(buf), f);
				buf[strlen(buf) - 1] = '\0';
				var = strtok(buf, "=");
				value = strtok(NULL, "=");
				if (var && value) {
					if (!strcasecmp(var, "mode"))
						telco_mode = atoi(value);
					else if (!strcasecmp(var, "iaxserver"))
						strncpy(iax_server, value, sizeof(iax_server)-1);
					else if (!strcasecmp(var, "iaxsecret"))
						strncpy(iax_secret, value, sizeof(iax_secret)-1);
					else if (!strcasecmp(var, "iaxpeer"))
						strncpy(iax_peer, value, sizeof(iax_peer)-1);
					else if (!strcasecmp(var, "iaxcontext"))
						strncpy(iax_context, value, sizeof(iax_context)-1);
					else if (!strcasecmp(var, "iaxusername"))
						strncpy(iax_username, value, sizeof(iax_username)-1);
					else if (!strcasecmp(var, "iaxpassword"))
						strncpy(iax_password, value, sizeof(iax_password)-1);
					else if (!strcasecmp(var, "iaxprefix"))
						strncpy(iax_prefix, value, sizeof(iax_prefix)-1);
					else if (!strcasecmp(var, "iaxport"))
						iax_port = atoi(value);
					else if (!strcasecmp(var, "nbrcomplete"))
						telco_register_nbrc(value);
					else fprintf(stderr, "Unknown variable: %s\n", var);
				}
			}
			fclose(f);
		} else
			return -1;
	} else
		return -1;
	return 0;
}

static void load_default_nbrcomplete(void)
{
	telco_register_nbrc("NXX-XXXX");
	telco_register_nbrc("1-NXX-NXX-XXXX");
	telco_register_nbrc("0-NXX-NXX-XXXX");
	telco_register_nbrc("411");
	telco_register_nbrc("611");
}

int telco_load_settings(void)
{
	int i;

	i = load_settings_from_file();

	if (i == -1) {
		telco_mode = 2;  /* We wanna use Asterisk */
		snprintf(iax_server, sizeof(iax_server), "iaxtel.com");
		snprintf(iax_context, sizeof(iax_context), "iaxtel");

		telco_save_settings();
	}
	else if (!i)
		return 0;

	load_default_nbrcomplete();
	return 0;
}

static int n_match(char *p, char *s)
{
	/* XXX Does not handle trailing spaces, parenthesis, dashes, etc XXX */
	while(*p && *s) {
		switch(toupper(*p)) {
		/* Ignore formatting characters */
		case ')':
		case '(':
		case ' ':
		case '-':
			p++;
			break;
		case 'N':
			if ((*s < '2') || (*s > '9'))
				return 0;
			s++;
			p++;
			break;
		case 'X':
			if ((*s < '0') || (*s > '9'))
				return 0;
			s++;
			p++;
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '*':
		case '#':
			if (*s != *p)
				return 0;
			s++;
			p++;
			break;
		default:
			fprintf(stderr, "Unknown pattern character: '%c'\n", *p);
			return 0;
		}
	}
	if (*p || *s) 
		return 0;
	return 1;
}

int telco_match_nbrc(char *s)
{
	/* Look to see if we have a matching number complete template */
	struct nbr_complete *n;
	n = nlist;
	while(n) {
		if (n_match(n->pattern, s)) {
			return 1;
		}
		n = n->next;
	}
	return 0;
}
