/*
 *	FILE: ui.c
 *	PROGRAM: Rat
 *	AUTHOR: Isidor Kouvelas + Colin Perkins + Orion Hodson
 * 	
 *	$Revision: 1.2 $
 * 	$Date: 1998/09/22 08:56:20 $
 *
 * Copyright (c) 1995,1996,1997 University College London
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, is permitted, for non-commercial use only, provided
 * that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the Computer Science
 *      Department at University College London
 * 4. Neither the name of the University nor of the Department may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 * Use of this software for commercial purposes is explicitly forbidden
 * unless prior written permission is obtained from the authors.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <ctype.h> 	/* for toupper() [csp] */
#include <math.h>
#include "version.h"
#include "bat_include.h"
#include "crypt.h"

#ifdef WIN32
extern int WinPutRegistry(ClientData, Tcl_Interp*, int ac, char** av);
extern int WinGetRegistry(ClientData, Tcl_Interp*, int ac, char** av);
extern int WinPutsCmd(ClientData, Tcl_Interp*, int ac, char** av);
extern int WinGetUserName(ClientData, Tcl_Interp*, int ac, char** av);
extern int Registry_Init(Tcl_Interp*);
#endif

Tcl_Interp *interp;	/* Interpreter for application. */

/* Temporary hack */
#define MAX_LIST_LENGTH		1000

static rtcp_dbentry	*list_contents[MAX_LIST_LENGTH];

/* MUST ADD INDEX IN DBENTRY AS WELL */

static char	comm[10000];	/* Command buffer */

/* ROUTINES ADDED TO HANDLE ENCRYPTION */

int Update_Key(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
        if (argc == 1) {
                Set_Key("");
        }
        else
        if (argc != 2) {
                i->result = "SetKey key";
                return (TCL_ERROR);
        }
        else
        {
                Set_Key(argv[1]);
        }
 
        return (TCL_OK);
}

void
eval_check(Tcl_Interp *i, char *c)
{
	if (Tcl_Eval(i, c) != TCL_OK) {
#ifdef DEBUG
		fprintf(stderr, "Command: %s\nError: %s\n", c, i->result);
#else
		fprintf(stderr, "TCL error: %s\n", i->result);
#endif
	}
}

void
start_playing(session_struct * session_pointer)
{
        session_pointer->playing_audio = TRUE;
        session_pointer->receive_audit_required = TRUE;
}

void
stop_playing(session_struct * session_pointer)
{
        session_pointer->playing_audio          = FALSE;
        session_pointer->receive_audit_required = TRUE;
}

/*
 * Update the on screen information for the given participant
 */

void
ui_info_update(rtcp_dbentry *e)
{
	char		*p;
	int		i;
	struct in_addr	in;

	/* If it is a new member allocate a position... */
	if (e->info_index == -1) {
		/* Start at 1 as 0 is for us... */
		for (i = 1; i < MAX_LIST_LENGTH; i++) {
			if (list_contents[i] == NULL) {
				break;
			}
		}
		assert(i < MAX_LIST_LENGTH);
		list_contents[i] = e;
		e->info_index = i;
	}
	sprintf(comm, "update_info %d ", e->info_index);
	p = comm + strlen(comm);

	/* This should be modified, since we could overwrite buffer here... */
	if (e->sentry->name != NULL) {
		sprintf(p, "{%s}", e->sentry->name);
		xmemchk();
	} else {
		if (e->sentry->cname != NULL) {
			sprintf(p, "{%s}", e->sentry->cname);
			xmemchk();
		} else {
			memcpy(&in.s_addr, &e->sentry->addr, sizeof (in.s_addr));
			sprintf(p, "{%s}", inet_ntoa(in));
			xmemchk();
		}
	}

	p = p + strlen(p);
#ifdef DEBUG
	if (e->sentry->tool == NULL) {
		sprintf(p, " black\n");
	} else {
		if ((strncmp(e->sentry->tool, "RAT", 3) == 0) || (strncmp(e->sentry->tool, "{RAT", 4) == 0)) {
			sprintf(p, " blue\n");
		} else {
			sprintf(p, " black\n");
		}
	}
	xmemchk();
#else
	sprintf(p, " black\n");
#endif
	eval_check(interp, comm);
}

/*
 * Remove a participant entry from the user interface
 */
void
ui_info_remove(rtcp_dbentry *e)
{
	sprintf(comm, "remove_info %d", e->info_index);
	eval_check(interp, comm);
	list_contents[e->info_index] = NULL;
	e->info_index = -1;
}

void
ui_info_activate(rtcp_dbentry *e)
{
	sprintf(comm, "activate_info %d", e->info_index);
	eval_check(interp, comm);
}

void
ui_info_gray(rtcp_dbentry *e)
{
	sprintf(comm, "gray_info %d", e->info_index);
	eval_check(interp, comm);
}

void
ui_info_deactivate(rtcp_dbentry *e)
{
	sprintf(comm, "deactivate_info %d", e->info_index);
	eval_check(interp, comm);
}

static int us_active = 0;

void
ui_info_activate_us(void)
{
	if (us_active == 1)
		return;
	sprintf(comm, "activate_info %d", 0);
	eval_check(interp, comm);
	us_active = 1;
}

void
ui_info_deactivate_us(void)
{
	if (us_active == 0)
		return;
	sprintf(comm, "deactivate_info %d", 0);
	eval_check(interp, comm);
	us_active = 0;
}

static void
update_stats(rtcp_dbentry *e)
{
	struct in_addr	in;
	char	encoding[100], *p, addr[20];
	int	l;

	if (e->encs[0] != -1) {
		strcpy(encoding, get_coding_name(e->encs[0]));
		for (l = 1, p = encoding; l < 10 && e->encs[l] != -1; l++) {
			p += strlen(p);
			*p++ = '+';
			strcpy(p, get_coding_name(e->encs[l]));
		}
	} else
		*encoding = 0;

	memcpy(&in.s_addr, &e->sentry->addr, sizeof (in.s_addr));
	sprintf(addr, "%s", inet_ntoa(in));

	sprintf(comm, "update_stats %d {"
		"Name:            %s\n"
		"Email:           %s\n"
		"Phone:           %s\n"
		"Location:        %s\n"
		"Tool:            %s\n"
		"CNAME:           %s\n"
		"Audio Encoding:  %s\n"
                "Audio Length:    %d ms\n"
		"Packets Received:            %5ld\n"
		"Packets Lost:                %5ld\n"
		"Packets Misordered:          %5ld\n"
		"Units Dropped (Jitter):      %5ld\n"
		"Network Timing Jitter:    %8.2f\n"
		"Instantaneous Loss Rate:  %8.2ld%%"
		"}", e->info_index,
		e->sentry->name == NULL? (e->sentry->cname == NULL? addr: e->sentry->cname): e->sentry->name,
		e->sentry->email == NULL? "": e->sentry->email,
		e->sentry->phone == NULL? "": e->sentry->phone,
		e->sentry->loc   == NULL? "": e->sentry->loc,
		e->sentry->tool  == NULL? "": e->sentry->tool,
		e->sentry->cname == NULL? "": e->sentry->cname,
		encoding,
                e->units_per_packet * 20,
		e->pckts_recv,
		e->lost_tot,
		e->misordered,
		e->jit_TOGed,
		e->jitter,
		(e->lost_frac * 100) >> 8);

	eval_check(interp, comm);
}

/*
 * Show information about a user in separate popup info window
 */
static int
stats_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		ind;	/* Index of required info */
	rtcp_dbentry	*e;

	if (argc != 2) {
		i->result = "stats participant_index";
		return TCL_ERROR;
	}

	if (Tcl_GetInt(i, argv[1], &ind)) {
		return TCL_ERROR;
	}

	/* If there are no participants etc... */
	if (ind <= 0) {
		return TCL_OK;
	}

	if ((e = list_contents[ind]) == NULL) {
		return TCL_OK;
	}

	update_stats(e);
	return TCL_OK;
}

static void
ui_update_input_port(session_struct *session_pointer)
{
	char	*mute;
	int	port;

	mute = session_pointer->sending_audio? "": "_mute";
	port = audio_get_iport(session_pointer->audio_fd);

	switch (port) {
	case AUDIO_MICROPHONE:
		sprintf(comm, ".r.c.gain.l2 configure -bitmap {mic%s}", mute);
		break;
	case AUDIO_LINE_IN:
		sprintf(comm, ".r.c.gain.l2 configure -bitmap {line_in%s}", mute);
		break;
	default:
		fprintf(stderr, "Invalid input port!\n");
		return ;
	}

	eval_check(interp, comm);
}

static void
ui_update_output_port(session_struct *session_pointer)
{
	char	*mute;
	int	port;

	mute = session_pointer->playing_audio? "": "_mute";
	port = audio_get_oport(session_pointer->audio_fd);

	switch (port) {
	case AUDIO_SPEAKER:
		sprintf(comm, ".r.c.vol.l1 configure -bitmap {speaker%s}", mute);
		break;
	case AUDIO_HEADPHONE:
		sprintf(comm, ".r.c.vol.l1 configure -bitmap {head%s}", mute);
		break;
	case AUDIO_LINE_OUT:
		sprintf(comm, ".r.c.vol.l1 configure -bitmap {line_out%s}", mute);
		break;
	default:
		fprintf(stderr, "Invalid output port!\n");
		return;
	}

	eval_check(interp, comm);
}

void
ui_input_level(int level)
{
	static int	ol;

	if (level > 15)
		level = 15;
	if (ol == level)
		return;

	sprintf(comm, "setHeight .r.c.gain.b2 %d", level);
	eval_check(interp, comm);
	ol = level;
}

void
ui_output_level(int level)
{
	static int	ol;

	if (level > 15) level = 15;
	if (ol == level) return;

	sprintf(comm, "setHeight .r.c.vol.b1 %d", level);
	eval_check(interp, comm);
	ol = level;
}
 
static void
ui_repair(int mode)
{
        switch(mode) {
        case REPAIR_NONE:
                sprintf(comm, "set repair_var None");
                break;
        case REPAIR_REPEAT:
                sprintf(comm, "set repair_var {Packet Repetition}");
                break;
		/*        case REPAIR_WAVEFORM_PM:
                sprintf(comm, "set repair_var {PM Waveform Substitution}");
                break;*/
        }
        eval_check(interp, comm);
}

static int
vol_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int	vol;
	session_struct *session_pointer = (session_struct *) ttp;

	if (argc != 2) {
		i->result = "vol_cmd volume";
		return TCL_ERROR;
	}

	if (Tcl_GetInt(i, argv[1], &vol))
		return TCL_ERROR;

	audio_set_volume(session_pointer->audio_fd, vol);
	return TCL_OK;
}

static int
gain_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int	gain;
	session_struct *session_pointer = (session_struct *) ttp;
        
        if (argc != 2) {
		i->result = "gain_cmd gain";
		return TCL_ERROR;
	}

	if (Tcl_GetInt(i, argv[1], &gain))
		return TCL_ERROR;

	/* This is wrong!
	 * gain = (int)(50.0 * log10((double)(gain + 1))); */
	audio_set_gain(session_pointer->audio_fd, gain);
	return TCL_OK;
}

static int
toggle_send_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct *session_pointer = (session_struct *) ttp;

        if (session_pointer->sending_audio) {
		stop_sending(session_pointer);
		eval_check(interp, ".r.c.gain.t2 configure -relief sunken");
	} else {
		start_sending(session_pointer);
		eval_check(interp, ".r.c.gain.t2 configure -relief raised");
	}

	ui_update_input_port(session_pointer);
	return TCL_OK;
}

static int
toggle_input_port_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct *session_pointer = (session_struct *) ttp;

	audio_next_iport(session_pointer->audio_fd);
	ui_update_input_port(session_pointer);
	return TCL_OK;
}

static int
toggle_play_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct *session_pointer = (session_struct *) ttp;

	if (session_pointer->playing_audio) {
		stop_playing(session_pointer);
		eval_check(interp, ".r.c.vol.t1 configure -relief sunken");
	} else {
		start_playing(session_pointer);
		eval_check(interp, ".r.c.vol.t1 configure -relief raised");
	}

	ui_update_output_port(session_pointer);
	return TCL_OK;
}

static int
toggle_output_port_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct *session_pointer = (session_struct *) ttp;

	audio_next_oport(session_pointer->audio_fd);
	ui_update_output_port(session_pointer);
	return TCL_OK;
}

static int
rate_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int	rate;
	session_struct *session_pointer = (session_struct *) ttp;
        
        if (argc != 2) {
		i->result = "rate_cmd rate";
		return TCL_ERROR;
	}
        rate = atoi(strtok(argv[1]," "));

#ifdef DEBUG
	printf("Setting rate to %d\n", rate);
#endif
	switch(rate) {
	case 20:
		session_pointer->units_per_pckt = 1;
		break;
	case 40:
		session_pointer->units_per_pckt = 2;
		break;
	case 80:
		session_pointer->units_per_pckt = 4;
		break;
        case 160:
                session_pointer->units_per_pckt = 8;
		break;
	default:
		fprintf(stderr, "error - can't set to this rate\n");
		break;
	}
	    
	return TCL_OK;
}

static int
output_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	
	session_struct *session_pointer = (session_struct *) ttp;
        
        if (argc != 2) {
		i->result = "output_cmd output";
		return TCL_ERROR;
	}

	switch(argv[1][0]) {
	case 'N':
#ifdef DEBUG	  
		printf("Net mutes mike\n");
#endif			
		session_pointer->voice_switching = NET_MUTES_MIKE;
		break;
	case 'M':
#ifdef DEBUG
		printf("Mike mutes net\n");
#endif			
		session_pointer->voice_switching = MIKE_MUTES_NET;
		break;
	case 'F':
#ifdef DEBUG	  
		printf("Full duplex\n");
#endif			
		session_pointer->voice_switching = FULL_DUPLEX;
		break;
	default:
		printf("Invalid output mode!\n");
		break;
	}

	return TCL_OK;
}

static int
redun_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int	encoding;

	session_struct *sp = (session_struct *) ttp;
  
	if (argc != 2) {
		i->result = "redundancy coding";
		return TCL_ERROR;
	}

	switch (argv[1][0]) {
	case 'P':
		encoding = PCM;
		break;
	case 'D':
		encoding = DVI;
		break;
	case 'L':
		encoding = LPC;
		break;
	case 'N':
		sp->num_encodings = 1;
		return TCL_OK;
	case 'G':
		encoding = GSM;
		break;
	default:
		return TCL_ERROR;
		break;
	}

	if (coding_value(sp->encodings[0]) < coding_value(encoding)) {
		/* Current primary scheme and requested redundancy
		 * do not match so do not change redundancy scheme */
		if (sp->num_encodings > 1) {
			sprintf(comm, "set secenc {%s}", get_coding_name(sp->encodings[1]));
			eval_check(interp, comm);
		} else {
			eval_check(interp, "set secenc NONE");
		}
	} else {
		sp->encodings[1] = encoding;
		sp->num_encodings = 2;
	}
	return TCL_OK;
}

static int
primary_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*sp = (session_struct *)ttp;
	int		encoding;
        
        if (argc != 2) {
		i->result = "primary encoding";
		return TCL_ERROR;
	}

	switch (argv[1][0]) {
	case '1':
		encoding = L16;
		break;
	case 'P':
		encoding = PCM;
		break;
	case 'D':
		encoding = DVI;
		break;
	case 'L':
		encoding = LPC;
		break;
	case 'G':
		encoding = GSM;
		break;
	default:
		return (TCL_ERROR);
		break;
	}

	sp->encodings[0] = encoding;

	if (sp->num_encodings > 1 && coding_value(sp->encodings[0]) < coding_value(sp->encodings[1])) {
		/* Current redundancy scheme and requested primary
		 * do not match so change redundancy scheme */
		sp->encodings[1] = sp->encodings[0];
		sprintf(comm, "set secenc {%s}", get_coding_name(sp->encodings[1]));
		eval_check(interp, comm);
	}
	return (TCL_OK);
}

static int
sync_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		sync = FALSE;
        
        if (argc != 2) {
		i->result = "sync 0|1";
		return TCL_ERROR;
	}

	if (Tcl_GetInt(i, argv[1], &sync)) {
		return TCL_ERROR;
	}
	
	return TCL_OK;
}

static int
lecture_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		lecture = FALSE;
	session_struct	*sp = (session_struct *)ttp;
        
        if (argc != 2) {
		i->result = "lecture 0|1";
		return TCL_ERROR;
	}
	if (Tcl_GetInt(i, argv[1], &lecture)) {
		return TCL_ERROR;
	}
	
	sp->lecture = lecture;
	
	return TCL_OK;
}

static int
bias_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		active = FALSE;
	session_struct	*sp    = (session_struct *)ttp;
        
        if (argc != 2) {
		i->result = "bias 0|1";
		return TCL_ERROR;
	}
	if (Tcl_GetInt(i, argv[1], &active)) {
		return TCL_ERROR;
	}
	
	sp->bc.active = active;

	return TCL_OK;
}

static int
mute_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		mute = FALSE, index;
	rtcp_dbentry	*e;
        
        if (argc != 3) {
		i->result = "mute index 0|1";
		return TCL_ERROR;
	}
	if (Tcl_GetInt(i, argv[1], &index)) {
		return TCL_ERROR;
	}
	if (Tcl_GetInt(i, argv[2], &mute)) {
		return TCL_ERROR;
	}

	if (index <= 0 || (e = list_contents[index]) == NULL) {
		i->result = "0";
	} else {
		e->mute = mute;
		i->result = "1";
	}

	return TCL_OK;
}

static int
powermeter_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		active = FALSE;
	session_struct	*sp    = (session_struct *)ttp;
        
        if (argc != 2) {
		i->result = "powermeter 0|1";
		return TCL_ERROR;
	}
	if (Tcl_GetInt(i, argv[1], &active)) {
		return TCL_ERROR;
	}
	
	sp->meter = active;
	ui_input_level(0);
	ui_output_level(0);

	return TCL_OK;
}

void
ui_update_bias(int state) {
	char	cmd[100];
	sprintf(cmd, "set bias_var %d",state);
	eval_check(interp, cmd);
}

static int
silence_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		silence;
	session_struct	*session_pointer = (session_struct *) ttp;
        
        if (argc != 2) {
		i->result = "silence 0|1";
		return TCL_ERROR;
	}

	if (Tcl_GetInt(i, argv[1], &silence))
		return TCL_ERROR;

	session_pointer->detect_silence = silence;
	
	return TCL_OK;
}

static int
repair_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	int		repair;
	session_struct	*session_pointer = (session_struct *) ttp;
        
        if (argc != 2) {
		i->result = "repair";
		return TCL_ERROR;
	}

        if (!strcmp(argv[1],"None")) {
		repair = REPAIR_NONE;
                sprintf(comm, "set repair_var {None}");
                eval_check(interp,comm);
        } else {
		repair = REPAIR_REPEAT;
                sprintf(comm, "set repair_var {Packet Repetition}");
                eval_check(interp,comm);
        } 

	session_pointer->repair = repair;
	return TCL_OK;
}

static char simplex_script[] = "set output_var {Mike mutes net}; output $output_var";

/*
 * This updates the look of the user interface when we get control
 * of the audio device. It is called only once...
 */
void
ui_update(session_struct *session_pointer)
{
	char	cmd[100];
	sprintf(cmd, ".r.c.vol.s1 set %d", audio_get_volume(session_pointer->audio_fd));
	eval_check(interp, cmd);
	sprintf(cmd, ".r.c.gain.s2 set %d", audio_get_gain(session_pointer->audio_fd));
	eval_check(interp, cmd);

	ui_update_output_port(session_pointer);

	if (session_pointer->playing_audio)
		eval_check(interp, ".r.c.vol.t1 configure -relief raised");
	else
		eval_check(interp, ".r.c.vol.t1 configure -relief sunken");

	ui_update_input_port(session_pointer);

	if (session_pointer->sending_audio)
		eval_check(interp, ".r.c.gain.t2 configure -relief raised");
	else
		eval_check(interp, ".r.c.gain.t2 configure -relief sunken");

	if (session_pointer->mode != TRANSCODER) {
		/* If we're using a real audio device, check if it's half duplex... */
		if (audio_duplex(session_pointer->audio_fd) == FALSE) {
			session_pointer->voice_switching = MIKE_MUTES_NET;
			eval_check(interp, simplex_script);

		}
	}

	sprintf(cmd, "set prenc {%s}", get_coding_name(session_pointer->encodings[0]));
	eval_check(interp, cmd);
	if (session_pointer->num_encodings > 1) {
		sprintf(cmd, "set secenc {%s}", get_coding_name(session_pointer->encodings[1]));
		eval_check(interp, cmd);
	} else {
		eval_check(interp, "set secenc NONE");
	}
}

static int
rtcp_name_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*session_pointer = (session_struct *) ttp;

        if (argc != 2) {
		i->result = "rtcp_name name";
		return (TCL_ERROR);
	}
	rtcp_set_attribute(session_pointer, RTCP_SDES_NAME, argv[1]);
	return TCL_OK;
}

static int
rtcp_email_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*session_pointer = (session_struct *) ttp;

        if (argc != 2) {
		i->result = "rtcp_email email";
		return (TCL_ERROR);
	}
	rtcp_set_attribute(session_pointer, RTCP_SDES_EMAIL, argv[1]);
	return TCL_OK;
}

static int
rtcp_phone_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*session_pointer = (session_struct *) ttp;

        if (argc != 2) {
		i->result = "rtcp_phone phone";
		return (TCL_ERROR);
	}
	rtcp_set_attribute(session_pointer, RTCP_SDES_PHONE, argv[1]);
	return TCL_OK;
}

static int
rtcp_loc_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*session_pointer = (session_struct *) ttp;

        if (argc != 2) {
		i->result = "rtcp_loc loc";
		return (TCL_ERROR);
	}
	rtcp_set_attribute(session_pointer, RTCP_SDES_LOC, argv[1]);
	return TCL_OK;
}

static int
play_file_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*session_pointer = (session_struct *) ttp;

        if (argc != 2) {
		i->result = "play file";
		return (TCL_ERROR);
	}

	if (session_pointer->in_file != NULL) {
		fclose(session_pointer->in_file);
		session_pointer->in_file = NULL;
	}
	if (strncmp(argv[1], "stop", 4)) {
		session_pointer->in_file = fopen(argv[1], "r");
		if (session_pointer->in_file == NULL) {
			perror("fopen infile");
		}
	}

	return TCL_OK;
}

static int
rec_file_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*session_pointer = (session_struct *) ttp;

        if (argc != 2) {
		i->result = "rec file";
		return (TCL_ERROR);
	}


	if (session_pointer->out_file != NULL) {
		fclose(session_pointer->out_file);
		session_pointer->out_file = NULL;
	}
	if (strncmp(argv[1], "stop", 4)) {
		session_pointer->out_file = fopen(argv[1], "w");
		if (session_pointer->out_file == NULL) {
			perror("fopen outfile");
		}
	}

	return TCL_OK;
}

static int
get_audio_cmd(ClientData ttp, Tcl_Interp *i, int argc, char *argv[])
{
	session_struct	*sp = (session_struct *) ttp;

        if (argc != 1) {
		i->result = "get_audio";
		return TCL_ERROR;
	}

	if (sp->have_device) {
		i->result = "Already have device!";
		return TCL_ERROR;
	}

	if (audio_device_take(sp) == FALSE) {
		lbl_cb_send_demand(sp);
	}
	return TCL_OK;
}

void
ui_show_audio_busy()
{
	eval_check(interp, "disable_audio_ctls");
}

void
ui_hide_audio_busy()
{
	eval_check(interp, "enable_audio_ctls");
}

#include "xbm/ucl.xbm"
#include "xbm/mic.xbm"
#include "xbm/mic_mute.xbm"
#include "xbm/speaker.xbm"
#include "xbm/speaker_mute.xbm"
#include "xbm/head.xbm"
#include "xbm/head_mute.xbm"
#include "xbm/line_out.xbm"
#include "xbm/line_out_mute.xbm"
#include "xbm/line_in.xbm"
#include "xbm/line_in_mute.xbm"
#include "xbm/rat_small.xbm"
#include "xbm/rat_med.xbm"
#include "xbm/rat2.xbm"

extern char init_ui_script[];

static int synchronize = 0;
static char *name      = NULL;
static char *display   = NULL;
static char *geometry  = NULL;

static Tk_ArgvInfo argTable[] = {
    {"-geometry",   TK_ARGV_STRING,   (char *) NULL, (char *) &geometry,    "Initial geometry for window"},
    {"-display",    TK_ARGV_STRING,   (char *) NULL, (char *) &display,     "Display to use"},
    {"-name",       TK_ARGV_STRING,   (char *) NULL, (char *) &name,        "Name to use for application"},
    {"-Xsync",      TK_ARGV_CONSTANT, (char *) 1,    (char *) &synchronize, "Use synchronous mode for display server"},
    {(char *) NULL, TK_ARGV_END,      (char *) NULL, (char *) NULL,         (char *) NULL}
};

extern void TkCreateXEventSource(void);

int
TkPlatformInit(Tcl_Interp *interp)
{
        Tcl_SetVar(interp, "tk_library", ".", TCL_GLOBAL_ONLY);
#ifndef WIN32
        TkCreateXEventSource();
#endif
        return (TCL_OK);
}

void
usage()
{
	int	argc = 2;
	char	*argv[3];
	
	argv[0] = "rat";
	argv[1] = "-help";
	argv[2] = 0;
	interp = Tcl_CreateInterp();
	if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, argTable, 0) != TCL_OK) {
		fprintf(stderr, "%s\n", interp->result);
		exit(1);
	}
	exit(1);
}

int
ui_init(session_struct *session_pointer, int argc, char **argv)
{
	char		*args, buffer[10];

	Tcl_FindExecutable(argv[0]);
	interp = Tcl_CreateInterp();

	args = Tcl_Merge(argc - 1, argv + 1);
	Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);

#ifndef WIN32
	ckfree(args);
#endif
	sprintf(buffer, "%d", argc - 1);
	Tcl_SetVar(interp, "argc", buffer, TCL_GLOBAL_ONLY);
	Tcl_SetVar(interp, "argv0", argv[0], TCL_GLOBAL_ONLY);
	Tcl_SetVar(interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);

	if (geometry != NULL)
		Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY);

	Tk_MainWindow(interp);
	/*
	 * There is no easy way of preventing the Init functions from
	 * loading the library files. Ignore error returns and load
	 * built in versions.
	 */
	Tcl_Init(interp);
	Tk_Init(interp);

	if (Tcl_VarEval(interp, TCL_LIBS, NULL) != TCL_OK) {
		fprintf(stderr, "TCL_LIBS error: %s\n", interp->result);
	}

	Tcl_CreateCommand(interp, "rtcp_name", 		rtcp_name_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "rtcp_email", 	rtcp_email_cmd,		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "rtcp_phone", 	rtcp_phone_cmd,		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "rtcp_loc", 		rtcp_loc_cmd,		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "set_vol", 		vol_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "set_gain", 		gain_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "toggle_send", 	toggle_send_cmd, 	(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "toggle_play", 	toggle_play_cmd, 	(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "toggle_input_port", 	toggle_input_port_cmd, 	(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "toggle_output_port", toggle_output_port_cmd, (ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "stats", 		stats_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "rate", 		rate_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "output", 		output_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "redundancy",		redun_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "powermeter",		powermeter_cmd, 	(ClientData) session_pointer, NULL);
        Tcl_CreateCommand(interp, "InstallKey",		Update_Key, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "lecture", 		lecture_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "bias", 		bias_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "sync", 		sync_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "primary", 		primary_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "silence", 		silence_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "play", 		play_file_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "rec", 		rec_file_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "repair", 		repair_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "mute",		mute_cmd, 		(ClientData) session_pointer, NULL);
	Tcl_CreateCommand(interp, "get_audio",          get_audio_cmd,          (ClientData) session_pointer, NULL);
#ifdef WIN32
	Registry_Init(interp);
	Tcl_CreateCommand(interp, "puts", WinPutsCmd, (ClientData)session_pointer, NULL);
    Tcl_CreateCommand(interp, "getusername", WinGetUserName, (ClientData)session_pointer, NULL);
#endif /* WIN32 */
	Tk_DefineBitmap(interp, Tk_GetUid("ucl"), ucl_bits, ucl_width, ucl_height);
	Tk_DefineBitmap(interp, Tk_GetUid("mic"), mic_bits, mic_width, mic_height);
	Tk_DefineBitmap(interp, Tk_GetUid("mic_mute"), mic_mute_bits, mic_mute_width, mic_mute_height);
	Tk_DefineBitmap(interp, Tk_GetUid("speaker"), speaker_bits, speaker_width, speaker_height);
	Tk_DefineBitmap(interp, Tk_GetUid("speaker_mute"), speaker_mute_bits, speaker_mute_width, speaker_mute_height);
	Tk_DefineBitmap(interp, Tk_GetUid("head"), head_bits, head_width, head_height);
	Tk_DefineBitmap(interp, Tk_GetUid("head_mute"), head_mute_bits, head_mute_width, head_mute_height);
	Tk_DefineBitmap(interp, Tk_GetUid("line_out"), line_out_bits, line_out_width, line_out_height);
	Tk_DefineBitmap(interp, Tk_GetUid("line_out_mute"), line_out_mute_bits, line_out_mute_width, line_out_mute_height);
	Tk_DefineBitmap(interp, Tk_GetUid("line_in"), line_in_bits, line_in_width, line_in_height);
	Tk_DefineBitmap(interp, Tk_GetUid("line_in_mute"), line_in_mute_bits, line_in_mute_width, line_in_mute_height);
	Tk_DefineBitmap(interp, Tk_GetUid("rat_small"), rat_small_bits, rat_small_width, rat_small_height);
	Tk_DefineBitmap(interp, Tk_GetUid("rat_med"),   rat_med_bits, rat_med_width, rat_med_height);
	Tk_DefineBitmap(interp, Tk_GetUid("rat2"), rat2_bits, rat2_width, rat2_height);

	sprintf(comm, "set ratversion {%s}", RAT_VERSION);
	eval_check(interp, comm);
	eval_check(interp, init_ui_script);

#if !defined(NDEBUG) && !defined(WIN32)
	sprintf(comm, ".r.b.ucl configure -background salmon");
	eval_check(interp, comm);
	sprintf(comm, ".r.b.v   configure -background salmon");
	eval_check(interp, comm);
#endif

	sprintf(comm, ".b.a.address configure -text {Dest: %s  Port: %d  TTL: %d}",
		session_pointer->maddress, session_pointer->rtp_port, session_pointer->ttl);
	eval_check(interp, comm);

	/* Update the UI to reflect the codec settings... */
	sprintf(comm, "set prenc {%s}", get_coding_name(session_pointer->encodings[0]));
	eval_check(interp, comm);
	sprintf(comm, "set secenc {%s}", get_coding_name(session_pointer->encodings[1]));
	eval_check(interp, comm);
	ui_repair(session_pointer->repair);
        sprintf(comm, "set silence_var %d", (session_pointer->detect_silence) ? 1 : 0);
        eval_check(interp, comm);
	update_lecture_mode(session_pointer);

	Tcl_ResetResult(interp);
	return (TRUE);
}

void
update_lecture_mode(session_struct *session_pointer)
{
	/* Update the UI to reflect the lecture mode setting...*/
	sprintf(comm, "set lecture_var %d", session_pointer->lecture);
	eval_check(interp, comm);
}




