/*
 * astconfig: Asterisk Configuration Tool
 *
 * Configure Asterisk
 *
 * IAX module support
 *
 * Copyright (C) 2002 Linux Support Services, Inc.
 *
 */

#include <gtk/gtk.h>
#include <asterisk/astconfig.h>
#include <asterisk/config.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "pipe.xpm"
#include "ksmiletris.xpm"	/* Friend */
#include "kdmconfig.xpm"	/* User */
#include "background.xpm"	/* Peer */



struct iax_entity {
	int type;
	char *name;					/* Points directly into the config */
	GtkWidget *widget;
	GtkWidget *pm;
	struct iax_entity *next;
};

static struct iax_entity *entities;

static struct ast_config *cfg;

static GtkWidget *mainw;
static GtkWidget *elist;	/* Entities */
static GtkWidget *saveb;
static GtkWidget *removeb;
static GtkWidget *edit;
static GtkWidget *regedit;
static GtkWidget *regremove;

static GtkWidget *portno;
static GtkWidget *bindaddr;
static GtkWidget *amaflags;
static GtkWidget *accountcode;
#if 0
static GtkWidget *gsm;
static GtkWidget *ulaw;
static GtkWidget *adpcm;
static GtkWidget *linear;
static GtkWidget *g723;
static GtkWidget *lpc10;
#endif
static GtkWidget *tos;
static GtkWidget *reglist;

static int visible = 0;

static int changes = 0;
static int loading = 0;

static struct iax_entity *current;
static struct ast_variable *currentreg;

static int iax_savechanges(void);

static void do_back(GtkWidget *w, void *data)
{
	gtk_widget_hide(mainw);
	visible = 0;
}

static void do_save(GtkWidget *w, void *data)
{
	iax_savechanges();
}

static struct iax_entity *iax_entity_new(struct ast_config *cfg, char *name)
{
	struct iax_entity *e;
	GtkWidget *hbox;
	GtkWidget *label;
	char *val;
	
	val = ast_variable_retrieve(cfg, name, "type");
	
	if (!val || (strcasecmp(val, "user") && strcasecmp(val, "friend") && strcasecmp(val, "peer"))) {
		fprintf(stderr, "'%s' lacks a type or valid type\n", name);
		return NULL;
	}
	e = g_new0(struct iax_entity, 1);
	hbox = gtk_hbox_new(5, FALSE);
	label = gtk_label_new(name);
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	
	if (!strcasecmp(val, "user")) 
		e->pm = make_pixmap_from_data(kdm);
	else if (!strcasecmp(val, "peer")) 
		e->pm = make_pixmap_from_data(background);
	else if (!strcasecmp(val, "friend"))
		e->pm = make_pixmap_from_data(mini_smiletris_xpm);
		
	gtk_box_pack_start(GTK_BOX(hbox), e->pm, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(hbox), label, TRUE, TRUE, 5);
	
	e->widget = gtk_list_item_new();
	gtk_object_set_user_data(GTK_OBJECT(e->widget), e);
	gtk_container_add(GTK_CONTAINER(e->widget), hbox);
	gtk_widget_show_all(e->widget);
		
	e->name = name;
	return e;
}

static void list_select(GtkList *list, GtkWidget *widget, gpointer data)
{
	struct iax_entity *entity = gtk_object_get_user_data(GTK_OBJECT(widget));
	current = entity;
	gtk_widget_set_sensitive(removeb, TRUE);
	gtk_widget_set_sensitive(edit, TRUE);
}

static void list_unselect(GtkList *list, GtkWidget *widget, gpointer data)
{
	current = NULL;	
	gtk_widget_set_sensitive(removeb, FALSE);
	gtk_widget_set_sensitive(edit, FALSE);
}

static void reg_select(GtkList *list, GtkWidget *widget, gpointer data)
{
	struct ast_variable *var = gtk_object_get_user_data(GTK_OBJECT(widget));
	currentreg = var;
	gtk_widget_set_sensitive(regremove, TRUE);
	gtk_widget_set_sensitive(regedit, TRUE);
}

static void reg_unselect(GtkList *list, GtkWidget *widget, gpointer data)
{
	currentreg = NULL;	
	gtk_widget_set_sensitive(regremove, FALSE);
	gtk_widget_set_sensitive(regedit, FALSE);
}

static char *toses[] = {
	"", "lowdelay", "throughput", "reliability", "mincost", "none"
};

static void set_portno(GtkWidget *w, void *nothing)
{
	if (!loading) {
		ast_variable_append_modify(cfg, "general", "port", gtk_entry_get_text(GTK_ENTRY(w)), 0, 0, 0);
		changes=1;
	}
}

static void set_bindaddr(GtkWidget *w, void *nothing)
{
	if (!loading) {
		ast_variable_append_modify(cfg, "general", "bindaddr", gtk_entry_get_text(GTK_ENTRY(w)), 0, 0, 0);
		changes=1;
	}
}

static void set_accountcode(GtkWidget *w, void *nothing)
{
	if (!loading) {
		ast_variable_append_modify(cfg, "general", "accountcode", gtk_entry_get_text(GTK_ENTRY(w)), 0, 0, 0);
		changes=1;
	}
}

static void set_tos(GtkWidget *w, void *nothing)
{
	if (!loading) {
		ast_variable_append_modify(cfg, "general", "tos", gtk_entry_get_text(GTK_ENTRY(w)), 0, 0, 0);
		changes=1;
	}
}

static GtkWidget *entwin;
static GtkWidget *entok;
static GtkWidget *ename;
static GtkWidget *etype;
static GtkWidget *epass;
static GtkWidget *ekeys;
static GtkWidget *eaddr;
static GtkWidget *eport;
static GtkWidget *edynamic;
static GtkWidget *ecname;
static GtkWidget *ecnum;
static GtkWidget *econtext;

static int entshowing;

static int entcancel(GtkWidget *w, void *nothing)
{
	gtk_widget_hide(entwin);
	entshowing = 0;
	return 1;
}

static void entsave(GtkWidget *w, void *nothing)
{
	
	gtk_widget_hide(entwin);
	entshowing = 0;
}

static void check_entokay(GtkWidget *w, void *nothing)
{
	if (strlen(gtk_entry_get_text(GTK_ENTRY(ename))))
		gtk_widget_set_sensitive(entok, TRUE);
	else
		gtk_widget_set_sensitive(entok, FALSE);
}

static char *cats[] = {
	"friend",
	"peer",
	"user"
};

static void build_entw(void)
{
	GtkWidget *cancel;
	GtkWidget *vbox;
	GtkWidget *frame;
	GtkWidget *table;
	GtkWidget *label;
	GtkWidget *bbox;
	GtkWidget *tbox;
	entwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(entwin), "AstConfig: Edit Entity");
	gtk_widget_realize(entwin);
	
	entok = gtk_button_new_with_label("OK");
	gtk_signal_connect(GTK_OBJECT(entok), "clicked", entsave, NULL);
	cancel = gtk_button_new_with_label("Cancel");
	gtk_signal_connect(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(entcancel), NULL);

	frame = gtk_frame_new("IAX Entity");
	table = gtk_table_new(5, 4, FALSE);
	vbox = gtk_vbox_new(FALSE, 5);
	bbox = gtk_hbox_new(FALSE, 5);	

	label = gtk_label_new("Entity Name:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 5, 5);
	
	ename = gtk_entry_new();
	gtk_widget_set_usize(ename, 100, 0);
	gtk_table_attach(GTK_TABLE(table), ename, 1, 2, 0, 1, 0, 0, 5, 5);
	gtk_signal_connect(GTK_OBJECT(ename), "changed", check_entokay, NULL);
	
	label = gtk_label_new("Type:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1, 0, 0, 5, 5);
	
	etype = widget_listbox(3, cats);
	gtk_widget_set_usize(etype, 100, 0);
	gtk_table_attach(GTK_TABLE(table), etype, 3, 4, 0, 1, 0, 0, 5, 5);

	label = gtk_check_button_new_with_label("MD5/Plaintext Password: ");
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 5, 5);

	epass = gtk_entry_new();
	gtk_widget_set_usize(epass, 100, 0);
	gtk_entry_set_editable(GTK_ENTRY(epass), FALSE);
	gtk_table_attach(GTK_TABLE(table), epass, 1, 2, 1, 2, 0, 0, 5, 5);
	gtk_widget_set_sensitive(epass, FALSE);
	
	label = gtk_check_button_new_with_label("RSA Authentication Keys: ");
	gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, 0, 0, 5, 5);

	ekeys = widget_keys(KEY_PUBLIC, 1);
	gtk_table_attach(GTK_TABLE(table), ekeys, 3, 4, 1, 2, 0, 0, 5, 5);
	gtk_widget_set_sensitive(ekeys, FALSE);


	tbox = gtk_hbox_new(FALSE, 5);
	label = gtk_label_new("Address:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_box_pack_start(GTK_BOX(tbox), label, FALSE, FALSE, 5);

	eaddr = gtk_entry_new();
	gtk_widget_set_usize(eaddr, 100, 0);
	gtk_box_pack_start(GTK_BOX(tbox), eaddr, FALSE, FALSE, 5);

	label = gtk_label_new("Port:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_box_pack_start(GTK_BOX(tbox), label, FALSE, FALSE, 5);
	
	eport = gtk_entry_new_with_max_length(5);
	gtk_widget_set_usize(eport, 50, 0);
	gtk_box_pack_start(GTK_BOX(tbox), eport, FALSE, FALSE, 5);
	
	gtk_table_attach(GTK_TABLE(table), tbox, 0, 2, 2, 3, 0, 0, 5, 5);

	edynamic = gtk_check_button_new_with_label("Dynamic (mobile) peer");
	gtk_table_attach(GTK_TABLE(table), edynamic, 2, 3, 2, 3, GTK_FILL, GTK_FILL, 5, 5);

	label = gtk_label_new("CallerID Number:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 5, 5);
	
	ecnum = gtk_entry_new();
	gtk_widget_set_usize(ecnum, 100, 0);
	gtk_table_attach(GTK_TABLE(table), ecnum, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 5, 5);

	label = gtk_label_new("CallerID Name:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 3, 4);
	
	ecname = gtk_entry_new();
	gtk_widget_set_usize(ecname, 100, 0);
	gtk_table_attach(GTK_TABLE(table), ecname, 3, 4, 3, 4, GTK_FILL, GTK_FILL, 5, 5);

	label = gtk_label_new("Context:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 4, 5);
	
	econtext = widget_contexts(0);
	gtk_widget_set_usize(econtext, 100, 0);
	gtk_table_attach(GTK_TABLE(table), econtext, 1, 2, 4, 5, GTK_FILL, GTK_FILL, 5, 5);

#if 0
	usepassword = label = gtk_radio_button_new_with_label(NULL, "Password:");
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 5, 5);
	gtk_signal_connect(GTK_OBJECT(label), "clicked", check_radios, NULL);
	
	password = gtk_entry_new();
	gtk_table_attach(GTK_TABLE(table), password, 1, 2, 3, 4, 0, 0, 5, 5);
	gtk_entry_set_visibility(GTK_ENTRY(password), FALSE);

	usekey = label = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(label)), "RSA Key:");
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, 0, 0, 5, 5);
	gtk_signal_connect(GTK_OBJECT(label), "clicked", check_radios, NULL);
	
	key = widget_keys(KEY_PRIVATE, 0);
	gtk_widget_set_usize(port, 50, 0);
	gtk_table_attach(GTK_TABLE(table), key, 1, 2, 4, 5, 0, 0, 5, 5);

	check_radios(NULL, NULL);
#endif
	
	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
	gtk_container_add(GTK_CONTAINER(frame), table);
	
	gtk_widget_set_usize(entok, 100, 30);
	gtk_widget_set_usize(cancel, 100, 30);
	gtk_box_pack_end(GTK_BOX(bbox), cancel, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox), entok, FALSE, FALSE, 5);
	
	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), gtk_hseparator_new(), FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
	gtk_widget_show_all(vbox);
	gtk_container_add(GTK_CONTAINER(entwin), vbox);
	gtk_signal_connect(GTK_OBJECT(entwin), "delete_event", GTK_SIGNAL_FUNC(entcancel), NULL);
}

static void load_ent(struct iax_entity *ent)
{
	if (!entwin) 
		build_entw();
	entshowing = 1;
	gtk_widget_set_sensitive(mainw, FALSE);
	gtk_widget_show(entwin);
	while(entshowing) 
		gtk_main_iteration_do(1);
	gtk_widget_set_sensitive(mainw, TRUE);
}

static void edit_ent(GtkWidget *w, void *nothing)
{
	load_ent(current);
}

static void add_ent(GtkWidget *w, void *nothing)
{
	current = NULL;
	load_ent(current);
}

static void del_ent(GtkWidget *w, void *nothing)
{
	if (!current)
		return;
	if (dialog_confirm(mainw, "Remove Entity", "Are you sure you wish to delete this IAX entity?", 1, "Remove IAX Entity"))  {
		ast_category_delete(cfg, current->name);
		gtk_widget_destroy(GTK_WIDGET(GTK_LIST(elist)->selection->data));
		changes = 1;
	}
}

static GtkWidget *regwin;
static GtkWidget *username;
static GtkWidget *password;
static GtkWidget *key;
static GtkWidget *host;
static GtkWidget *port;
static GtkWidget *usekey;
static GtkWidget *usepassword;
static GtkWidget *regok;
static int regshowing;


static void check_isokay(GtkWidget *w, void *nothing)
{
	if (strlen(gtk_entry_get_text(GTK_ENTRY(host))))
		gtk_widget_set_sensitive(regok, TRUE);
	else
		gtk_widget_set_sensitive(regok, FALSE);
}
static void check_radios(GtkWidget *w, void *nothing)
{
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(usepassword))) {
		gtk_widget_set_sensitive(key, FALSE);
		gtk_widget_set_sensitive(password, TRUE);
	} else {
		gtk_widget_set_sensitive(key, TRUE);
		gtk_widget_set_sensitive(password, FALSE);
	}
}

static int regcancel(GtkWidget *w, void *nothing)
{
	gtk_widget_hide(regwin);
	regshowing = 0;
	return 1;
}

static char *hide_password(char *regstr)
{
	static char tmp[256];
	static char copy[256];
	char *user, *pass, *host;
	user = copy;
	strncpy(copy, regstr, sizeof(copy) - 1);
	host = strchr(copy, '@');
	if (!host) {
		strncpy(tmp, regstr, sizeof(tmp) - 1);
		return tmp;
	}
	*host = '\0';
	host++;
	pass = strchr(user, ':');
	if (pass) {
		*pass = '\0';
		pass++;
	}
	if (pass) {
		if (pass[0] == '[') {
			snprintf(tmp, sizeof(tmp), "%s:%s@%s", user, pass, host);
		} else {
			snprintf(tmp, sizeof(tmp), "%s:<password>@%s", user, host);
		}
	} else {
		snprintf(tmp, sizeof(tmp), "%s@%s", user,host);
	}
	return tmp;
}
	
static void regsave(GtkWidget *w, void *nothing)
{
	char tmp[256];
	char *chost;
	char *cpass;
	char *cport;
	char *cuser;
	char *ckey;
	int cusekey;
	struct ast_variable *var;
	GtkWidget *tmpw;
	GList *l;
	
	gtk_widget_hide(regwin);
	regshowing = 0;
	/* Build new string */
	cuser = gtk_entry_get_text(GTK_ENTRY(username));
	chost = gtk_entry_get_text(GTK_ENTRY(host));
	cpass = gtk_entry_get_text(GTK_ENTRY(password));
	cport = gtk_entry_get_text(GTK_ENTRY(port));
	ckey = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(key)->entry));
	cusekey = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(usekey));
	if (strlen(cuser)) {
		if (!cusekey && strlen(cpass)) 
			snprintf(tmp, sizeof(tmp), "%s:%s@%s", cuser, cpass, chost);
		else if (usekey && strlen(ckey))
			snprintf(tmp, sizeof(tmp), "%s:[%s]@%s", cuser, ckey, chost);
		else
			snprintf(tmp, sizeof(tmp), "%s@%s", cuser, chost);
	} else {
		snprintf(tmp, sizeof(tmp), "%s", chost);
	}
	if (strlen(cport)) {
		strcat(tmp, ":");
		strcat(tmp, cport);
	}
	if (currentreg) {
		/* Edit */
		if (strcmp(currentreg->value, tmp)) {
			ast_variable_append_modify(cfg, "general", currentreg->name, tmp, 0, 0, 0);
			changes = 1;
		}
	} else {
		/* Add */
		var = ast_variable_append_modify(cfg, "general", "register", tmp, 0, 1, 0);
		if (var) {
			var->object = 1;
			tmpw = gtk_list_item_new_with_label(hide_password(var->value));
			gtk_widget_show(tmpw);
			/* Must keep a pointer to the original name */
			gtk_object_set_user_data(GTK_OBJECT(tmpw), var);
			l = g_list_append(NULL, tmpw);
			gtk_list_append_items(GTK_LIST(reglist), l);
		} else 
			fprintf(stderr, "Huh?  append/modify returned NULL\n");
		changes = 1;
	}
}

static void build_regw(void)
{
	GtkWidget *cancel;
	GtkWidget *vbox;
	GtkWidget *frame;
	GtkWidget *table;
	GtkWidget *label;
	GtkWidget *bbox;
	regwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(regwin), "AstConfig: Edit Registration");
	gtk_widget_realize(regwin);
	
	regok = gtk_button_new_with_label("OK");
	gtk_signal_connect(GTK_OBJECT(regok), "clicked", regsave, NULL);
	cancel = gtk_button_new_with_label("Cancel");
	gtk_signal_connect(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(regcancel), NULL);

	frame = gtk_frame_new("IAX Registration");
	table = gtk_table_new(5, 2, FALSE);
	vbox = gtk_vbox_new(FALSE, 5);
	bbox = gtk_hbox_new(FALSE, 5);	

	label = gtk_label_new("Peername/Username:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 5, 5);
	
	username = gtk_entry_new();
	gtk_table_attach(GTK_TABLE(table), username, 1, 2, 0, 1, 0, 0, 5, 5);
	
	label = gtk_label_new("Remote Host:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 5, 5);
	
	host = gtk_entry_new();
	gtk_table_attach(GTK_TABLE(table), host, 1, 2, 1, 2, 0, 0, 5, 5);
	gtk_signal_connect(GTK_OBJECT(host), "changed", check_isokay, NULL);

	label = gtk_label_new("Port:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, 0, 0, 5, 5);
	
	port = gtk_entry_new_with_max_length(5);
	gtk_widget_set_usize(port, 50, 0);
	gtk_table_attach(GTK_TABLE(table), port, 1, 2, 2, 3, 0, 0, 5, 5);

	usepassword = label = gtk_radio_button_new_with_label(NULL, "Password:");
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 5, 5);
	gtk_signal_connect(GTK_OBJECT(label), "clicked", check_radios, NULL);
	
	password = gtk_entry_new();
	gtk_table_attach(GTK_TABLE(table), password, 1, 2, 3, 4, 0, 0, 5, 5);
	gtk_entry_set_visibility(GTK_ENTRY(password), FALSE);

	usekey = label = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(label)), "RSA Key:");
	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, 0, 0, 5, 5);
	gtk_signal_connect(GTK_OBJECT(label), "clicked", check_radios, NULL);
	
	key = widget_keys(KEY_PRIVATE, 0);
	gtk_widget_set_usize(port, 50, 0);
	gtk_table_attach(GTK_TABLE(table), key, 1, 2, 4, 5, 0, 0, 5, 5);

	check_radios(NULL, NULL);
	
	gtk_container_set_border_width(GTK_CONTAINER(table), 5);
	gtk_container_add(GTK_CONTAINER(frame), table);
	
	gtk_widget_set_usize(regok, 100, 30);
	gtk_widget_set_usize(cancel, 100, 30);
	gtk_box_pack_end(GTK_BOX(bbox), cancel, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox), regok, FALSE, FALSE, 5);
	
	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), gtk_hseparator_new(), FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
	gtk_widget_show_all(vbox);
	gtk_container_add(GTK_CONTAINER(regwin), vbox);
	gtk_signal_connect(GTK_OBJECT(regwin), "delete_event", GTK_SIGNAL_FUNC(regcancel), NULL);
}

static  void load_reg(struct ast_variable *var)
{
	char tmpstr[256];
	char *cusername=NULL;
	char *cpassword=NULL;
	int ckey = 0;
	char *chost=NULL;
	char *cportno=NULL;
	if (!regwin) 
		build_regw();
	if (var) {
		strncpy(tmpstr, var->value, sizeof(tmpstr));
		chost = strchr(tmpstr, '@');
		if (chost)  {
			*chost = '\0';
			chost++;
			cusername = tmpstr;
		} else
			chost = tmpstr;
		cportno = strchr(chost, ':');
		if (cportno) {
			*cportno = '\0';
			cportno++;
		}
		if (cusername) {
			cpassword = strchr(cusername, ':');
			if (cpassword) {
				*cpassword = '\0';
				cpassword++;
				if (strlen(cpassword) > 1) {
					if ((cpassword[0] == '[') && cpassword[(strlen(cpassword) - 1)] == ']') {
						ckey=1;
						cpassword++;
						cpassword[(strlen(cpassword) - 1)] = '\0';
					}
				}
			}
		}
	}
	if (!chost)
		chost = "";
	if (!cusername)
		cusername = "";
	if (!cportno)
		cportno = "";
	if (!cpassword)
		cpassword = "";
	gtk_entry_set_text(GTK_ENTRY(host), chost);
	gtk_entry_set_text(GTK_ENTRY(port), cportno);
	gtk_entry_set_text(GTK_ENTRY(username), cusername);
	if (ckey) {
		gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(key)->entry), cpassword);
		gtk_entry_set_text(GTK_ENTRY(password), "");
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(usekey), TRUE);
	} else {
		gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(key)->entry), "");
		gtk_entry_set_text(GTK_ENTRY(password), cpassword);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(usepassword), TRUE);
	}
	regshowing = 1;
	gtk_widget_set_sensitive(mainw, FALSE);
	gtk_widget_show(regwin);
	while(regshowing) 
		gtk_main_iteration_do(1);
	gtk_widget_set_sensitive(mainw, TRUE);
	
}

static void edit_reg(GtkWidget *w, void *nothing)
{
	load_reg(currentreg);
}

static void add_reg(GtkWidget *w, void *nothing)
{
	currentreg = NULL;
	load_reg(currentreg);
}

static void del_reg(GtkWidget *w, void *nothing)
{
	if (!currentreg)
		return;
	if (dialog_confirm(mainw, "Remove Registration", "Are you sure you wish to delete this registration?", 1, "Remove Registration"))  {
		ast_variable_delete(cfg, "general", currentreg->name, NULL);
		gtk_widget_destroy(GTK_WIDGET(GTK_LIST(reglist)->selection->data));
		changes = 1;
	}
}

static void build_main(void)
{
	GtkWidget *frame;
	GtkWidget *hbox;
	GtkWidget *vbox;
	GtkWidget *bbox;
	GtkWidget *sbox;
	GtkWidget *gvbox;
	GtkWidget *backb;
	GtkWidget *label;
	
	GtkWidget *add;
	GtkWidget *tmpf;

	mainw = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_widget_realize(mainw);
	gtk_window_set_title(GTK_WINDOW(mainw), "AstConfig: IAX Configuration");

	elist = gtk_list_new();

	tmpf = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(tmpf), GTK_SHADOW_IN);
	gtk_container_add(GTK_CONTAINER(tmpf), elist);

	frame = gtk_frame_new("IAX Entities");
	
	gtk_widget_set_usize(frame,0, 300);

	/* Silly box for space around list, but we'll use it anyway */
	sbox = gtk_vbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(sbox), tmpf, TRUE, TRUE, 5);
	gtk_container_add(GTK_CONTAINER(frame), sbox);
	gtk_container_set_border_width(GTK_CONTAINER(sbox), 5);

	gtk_signal_connect(GTK_OBJECT(elist), "select-child", list_select, NULL);
	gtk_signal_connect(GTK_OBJECT(elist), "unselect-child", list_unselect, NULL);

	gvbox = gtk_hbox_new(FALSE, 5);
	add = gtk_button_new_with_label("Add...");
	gtk_widget_set_usize(add, 70, 25);
	gtk_signal_connect(GTK_OBJECT(add), "clicked", add_ent, NULL);
	removeb = gtk_button_new_with_label("Remove...");
	gtk_widget_set_sensitive(removeb, FALSE);
	gtk_widget_set_usize(removeb, 70, 25);
	gtk_signal_connect(GTK_OBJECT(removeb), "clicked", del_ent, NULL);
	edit = gtk_button_new_with_label("Edit...");
	gtk_widget_set_sensitive(edit, FALSE);
	gtk_widget_set_usize(edit, 70, 25);
	gtk_signal_connect(GTK_OBJECT(edit), "clicked", edit_ent, NULL);
	
	gtk_box_pack_start(GTK_BOX(gvbox), add, FALSE, FALSE, 10);
	gtk_box_pack_start(GTK_BOX(gvbox), edit, FALSE, FALSE, 10);
	gtk_box_pack_start(GTK_BOX(gvbox), removeb, FALSE, FALSE, 10);

	gtk_box_pack_start(GTK_BOX(sbox), gvbox, FALSE, FALSE, 5);
	


	vbox = gtk_vbox_new(FALSE, 0);
	hbox = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 5);

	backb = gtk_button_new_with_label("Return to main");
	gtk_signal_connect(GTK_OBJECT(backb), "clicked", do_back, NULL);
	gtk_signal_connect(GTK_OBJECT(mainw), "delete_event", GTK_SIGNAL_FUNC(do_back), NULL);
	gtk_widget_set_usize(backb, 140, 30);

	saveb = gtk_button_new_with_label("Save IAX Changes");
	gtk_signal_connect(GTK_OBJECT(saveb), "clicked", do_save, NULL);
	gtk_widget_set_usize(saveb, 140, 30);
	
	bbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox), backb, FALSE, FALSE, 5);
	gtk_box_pack_end(GTK_BOX(bbox), saveb, FALSE, FALSE, 5);

	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), gtk_hseparator_new(), FALSE, FALSE, 5);
	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 5);
	
	frame = gtk_frame_new("General Settings");
	gvbox = gtk_table_new(7, 3, FALSE);

	label = gtk_label_new("Port Number: ");
	portno = gtk_entry_new_with_max_length(5);
	gtk_signal_connect(GTK_OBJECT(portno), "changed", set_portno, NULL);
	gtk_widget_set_usize(portno, 50, 0);
	gtk_table_attach(GTK_TABLE(gvbox), label, 0, 1, 0, 1, 0, 0, 5, 5);
	gtk_table_attach(GTK_TABLE(gvbox), portno, 1, 2, 0, 1, 0, 0, 5, 5);

	label = gtk_label_new("Bind Address: ");
	bindaddr = gtk_entry_new_with_max_length(15);
	gtk_signal_connect(GTK_OBJECT(bindaddr), "changed", set_bindaddr, NULL);
	gtk_widget_set_usize(bindaddr, 120, 0);
	gtk_table_attach(GTK_TABLE(gvbox), label, 0, 1, 1, 2, 0, 0, 5, 5);
	gtk_table_attach(GTK_TABLE(gvbox), bindaddr, 1, 3, 1, 2, 0, 0, 5, 5);

	label = gtk_label_new("Def. AMA Flags: ");
	amaflags = widget_amaflags();
	gtk_widget_set_usize(amaflags, 120, 0);
	gtk_table_attach(GTK_TABLE(gvbox), label, 0, 1, 2, 3, 0, 0, 5, 5);
	gtk_table_attach(GTK_TABLE(gvbox), amaflags, 1, 3, 2, 3, 0, 0, 5, 5);


	label = gtk_label_new("Def. Account Code: ");
	accountcode = gtk_entry_new_with_max_length(15);
	gtk_signal_connect(GTK_OBJECT(accountcode), "changed", set_accountcode, NULL);
	gtk_widget_set_usize(accountcode, 120, 0);
	gtk_table_attach(GTK_TABLE(gvbox), label, 0, 1, 3, 4, 0, 0, 5, 5);
	gtk_table_attach(GTK_TABLE(gvbox), accountcode, 1, 3, 3, 4, 0, 0, 5, 5);

	label = gtk_label_new("(Type of Service (TOS):");
	tos = widget_listbox(6, toses);
	gtk_signal_connect(GTK_OBJECT(GTK_COMBO(tos)->entry), "changed", set_tos, NULL);
	gtk_widget_set_usize(tos, 120, 0);
	gtk_table_attach(GTK_TABLE(gvbox), label, 0, 1, 4, 5, 0, 0, 5, 5);
	gtk_table_attach(GTK_TABLE(gvbox), tos, 1, 3, 4, 5, 0, 0, 5, 5);


	reglist = gtk_list_new();

	tmpf = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(tmpf), GTK_SHADOW_IN);
	gtk_container_add(GTK_CONTAINER(tmpf), reglist);

	label = gtk_label_new("Registrations:");
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_table_attach(GTK_TABLE(gvbox), label, 0, 1, 5, 6, 0,  0, 0, 5);

	gtk_table_attach(GTK_TABLE(gvbox), tmpf, 0, 3, 6, 7, GTK_EXPAND|GTK_FILL,  GTK_EXPAND|GTK_FILL, 5, 5);
	gtk_signal_connect(GTK_OBJECT(reglist), "select-child", reg_select, NULL);
	gtk_signal_connect(GTK_OBJECT(reglist), "unselect-child", reg_unselect, NULL);

	bbox = gtk_hbox_new(FALSE, 5);
	add = gtk_button_new_with_label("Add...");
	gtk_signal_connect(GTK_OBJECT(add), "clicked", add_reg, NULL);
	regedit = gtk_button_new_with_label("Edit...");
	gtk_signal_connect(GTK_OBJECT(regedit), "clicked", edit_reg, NULL);
	gtk_widget_set_sensitive(regedit, FALSE);
	regremove = gtk_button_new_with_label("Remove...");
	gtk_signal_connect(GTK_OBJECT(regremove), "clicked", del_reg, NULL);
	gtk_widget_set_sensitive(regremove, FALSE);
	gtk_box_pack_start(GTK_BOX(bbox), add, FALSE, FALSE, 0);
	gtk_widget_set_usize(add, 70, 25);
	gtk_box_pack_start(GTK_BOX(bbox), regedit, FALSE, FALSE, 0);
	gtk_widget_set_usize(regedit, 70, 25);
	gtk_box_pack_start(GTK_BOX(bbox), regremove, FALSE, FALSE, 0);
	gtk_widget_set_usize(regremove, 70, 25);
	gtk_table_attach(GTK_TABLE(gvbox), bbox, 0, 3, 7, 8, 0, 0, 5, 5);

	gtk_container_set_border_width(GTK_CONTAINER(gvbox), 5);
	gtk_container_add(GTK_CONTAINER(frame), gvbox);
	
	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 5);

	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);

	gtk_container_add(GTK_CONTAINER(mainw), vbox);
}

static int iax_load(void)
{
	struct ast_variable *var;
	char *ent;
	struct iax_entity *e, *pe;
	GList *l;
	loading = 1;
	if (!mainw)
		build_main();
	if (cfg)
		ast_destroy(cfg);

	e = entities;
	while(e) {
		pe = e;
		e = e->next;
		free(pe);
	}
	entities = NULL;
	
	gtk_entry_set_text(GTK_ENTRY(portno), "");
	gtk_entry_set_text(GTK_ENTRY(bindaddr), "");
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(amaflags)->entry), "");
	gtk_entry_set_text(GTK_ENTRY(accountcode), "");
	gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(tos)->entry), "");
	gtk_list_clear_items(GTK_LIST(elist), 0, -1);
	gtk_list_clear_items(GTK_LIST(reglist), 0, -1);
	
	cfg = ast_load("iax.conf");
	if (cfg) {
		var = ast_variable_browse(cfg, "general");
		while(var) {
			if (!strcasecmp(var->name, "port")) {
				gtk_entry_set_text(GTK_ENTRY(portno), var->value);
			} else if (!strcasecmp(var->name, "bindaddr")) {
				gtk_entry_set_text(GTK_ENTRY(bindaddr), var->value);
			} else if (!strcasecmp(var->name, "amaflags")) {
				gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(amaflags)->entry), var->value);
			} else if (!strcasecmp(var->name, "tos")) {
				gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(tos)->entry), var->value);
			} else if (!strcasecmp(var->name, "accountcode")) {
				gtk_entry_set_text(GTK_ENTRY(accountcode), var->value);
			} else if (!strcasecmp(var->name, "register")) {
				GtkWidget *tmp = gtk_list_item_new_with_label(hide_password(var->value));
				gtk_widget_show(tmp);
				/* Must keep a pointer to the orignal name */
				gtk_object_set_user_data(GTK_OBJECT(tmp), var);
				l = g_list_append(NULL, tmp);
				gtk_list_append_items(GTK_LIST(reglist), l);
			}
			var = var->next;
		}
		ent = ast_category_browse(cfg, NULL);
		while(ent) {
			if (strcasecmp(ent, "general")) {
				e = iax_entity_new(cfg, ent);
				if (e) {
					e->next = entities;
					entities = e;
					l = g_list_append(NULL, e->widget);
					gtk_list_append_items(GTK_LIST(elist), l);
					
				}
			}
			ent = ast_category_browse(cfg, ent);
		}
	}
	changes = 0;
	loading = 0;
	return 0;
}

static void show_main(void)
{
	gtk_widget_show_all(mainw);
	visible = 1;
}

static int iax_launch(void)
{
	int oldchanges = 999;
	if (!mainw) {
		iax_load();
		show_main();
	}
	show_main();
	while (visible) {
		if (changes != oldchanges) {
			if (changes) 
				gtk_widget_set_sensitive(saveb, TRUE);
			else
				gtk_widget_set_sensitive(saveb, FALSE);
			oldchanges = changes;
		}
		gtk_main_iteration_do(0);
	}
	return 0;
}

static int iax_changes(void)
{
	return changes;
}

static int iax_needrestart(void)
{
	printf("NeedRestart?!\n");
	return 0;
}

static int iax_savechanges(void)
{
	ast_save("iax.conf", cfg, "astconfig-mod_iax");
	changes = 0;
	return 0;
}


struct config_module modiax = {
	"Inter Asterisk eXchange (IAX)",
	"Inter-Asterisk eXchange is a powerful VoIP protocol used natively by "
"Asterisk for communicating with other Asterisk PBX's and compatible "
"products such as Gnophone and SNOM Phones.\n\nIAX is more efficient than "
"other RTP based protocols such as H.323 and SIP, and provides features "
"not found in those protocols, such as the ability to transparently "
"interoperate with NAT/PAT and IP Masquerade firewalls, remote dialplan "
"support, internationalization, context specification, authentication.",
	pipe_xpm,
	iax_launch,
	iax_changes,
	iax_needrestart,
	iax_savechanges,
	iax_load
	
};

int mod_init(void)
{
	printf("Initialized IAX module\n");
	module_register(&modiax);
	return 0;
}
