/*
 *
 *	servercomm.c
 *
 *	HNMS User Interface
 *	HNMS 2.0
 *
 *	February 1994
 *
 *	Leslie Schlecht
 *	Computer Sciences Corporation
 *	Numerical Aerodynamic Simulation Systems Division
 *	NASA Ames Research Center
 *
 *	Copyright (c) 1994 Leslie Schlecht
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 1, or (at your option)
 *	any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include	<stdlib.h>
#include	<stdio.h>
#include	<string.h>
#include	<sys/types.h>
#include	<sys/socket.h>
#include	<netinet/in.h>
#include	<netdb.h>
#include	<arpa/inet.h>

#include	<X11/StringDefs.h>
#include	<X11/Intrinsic.h>
#include	<X11/Core.h>
#include	<Xm/Xm.h>
#include	<Xm/MwmUtil.h>
#include	<Xm/Form.h>
#include	<Xm/Frame.h>
#include	<Xm/Label.h>
#include	<Xm/RowColumn.h>
#include	<Xm/Text.h>
#include	<Xm/PushB.h>
#include	<Xm/List.h>
#include	<Xm/ScrolledW.h>
#include	<Xm/Separator.h>

#include	"stdhnms.h"
#include	"defines.h"
#include	"externs.h"
#include	"viewpanel.h"
#include	"xsupport.h"
#include	"servercomm.h"

#define		WAITFOR		10
#define		NSERVERS	32
#define		NMESGTYPES	22

static Widget	community_text;
static Widget	server_list;
static Widget	server_text, server_host, ui_modid;
static Widget	connect_button, disconnect_button;
static Widget	server_status, since_time, update_face;
static Widget	server_label, server_time;
static Widget	message_text, queue_text, stat_button;

static XmStringTable	list;
static int	is_connected=0, *pl, pc, lc, pos, waiting=0, trying=0, recon=0;
static int	flashing=0, closeme=0, server_goodbye=0;
static char	*host_name=NULL;
static char	*server_name = NULL, *comname[NSERVERS];
static char	*community_name = NULL, com_name_env[BUFSIZ];
static char	buf[BUFSIZ];
static int	to_id = 0, HNMPversion=0, my_id;
static VIEWPANEL	*serverpanel;
static caddr_t	serverlog;
static int	message_count[NMESGTYPES];


/*
 *	Cancel connection procedure or disconnect from server.
 */
void
CancelConnect()
	{
	if (waiting) {
		waiting = 0;
		trying = 0;
		HNMP_close(0);
		UpdateServerPanel(2, NULL, 0);
		}
	else {
		is_connected = 0;
		UpdateServerPanel(3, NULL, 0);
		}
	XtSetSensitive(server_list, 1);
	XtSetSensitive(connect_button, 1);
	XtSetSensitive(server_text, 1);
	XtSetSensitive(community_text, 1);
	}


/*
 *	Close an HNMP connection.
 */
int
CloseHNMP(send_goodbye)
int	send_goodbye;
	{
	Message		m;

	/* send a goodbye message */
	if (send_goodbye) {
		m = Message_create(HNMP_GOODBYE);
		if (HNMP_Message_enqueue(m, to_id) < 0) {
			HNMS_err("HNMP_Message_enqueue");
			return(0);
			}
		}
	/* close up */
	HNMP_close(0);
	return(1);
	}


/*
 *	Apply configuration file record.
 */
void
ConfigureServerPanel(variable, value)
char	*variable;
char	*value;
	{
	if (strncmp(variable, "host", 4) == 0)
		XmTextSetString(server_text, value);
	else if (strncmp(variable, "community", 9) == 0)
		XmTextSetString(community_text, value);
	}


/*
 *	Create the server panel.
 */
void
CreateServerPanel(btn, obtn, uf, sn, ct)
Widget	btn, obtn, uf, sn, ct;
	{
	XmString	xs, xs1, xs2, xs3;
	Widget		topform, form1, button, label, m, f, l1, b, form2;

	update_face = uf;
	server_label = sn;
	server_time = ct;
	serverpanel = CreateViewPanel("Server", "server", 600, 0, "server", 0,
		0, 0);
	serverpanel->button = btn;
	XtAddCallback(obtn, XmNactivateCallback, OpenServerPanel, NULL);

	/* main form */
	topform = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		serverpanel->viewform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNleftOffset, 5,
		XmNrightAttachment, XmATTACH_FORM,
		XmNrightOffset, 5,
		XmNtopAttachment, XmATTACH_FORM,
		XmNtopOffset, 5,
		XmNbottomAttachment, XmATTACH_NONE,
		NULL);
	f = XtVaCreateManagedWidget("panedwindow",
		xmSeparatorWidgetClass,
		serverpanel->viewform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_NONE,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, topform,
		XmNtopOffset, 5,
		XmNorientation, XmHORIZONTAL,
		NULL);
	/* server log */
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		serverpanel->viewform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNleftOffset, 5,
		XmNrightAttachment, XmATTACH_FORM,
		XmNrightOffset, 5,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNbottomOffset, 5,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, f,
		XmNtopOffset, 5,
		NULL);
	serverlog = CreateLog(f, "ServerLog");


	form2 = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		topform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_NONE,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form2,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_NONE,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_NONE,
		NULL);
	disconnect_button = XtVaCreateManagedWidget("pb",
		xmPushButtonWidgetClass,
		f,
		XmNlabelString, (xs=X_STR("Disconnect")),
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_NONE,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNresizable, False,
		NULL);
	XmStringFree(xs);
	XtAddCallback(disconnect_button, XmNactivateCallback, SelectConnect,
		(XtPointer)2);
	connect_button = XtVaCreateManagedWidget("pb",
		xmPushButtonWidgetClass,
		f,
		XmNlabelString, (xs=X_STR("Connect")),
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_WIDGET,
		XmNrightWidget, disconnect_button,
		XmNrightOffset, 10,
		XmNresizable, False,
		NULL);
	XmStringFree(xs);
	XtAddCallback(connect_button, XmNactivateCallback, SelectConnect,
		(XtPointer)1);
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form2,
		XmNtopAttachment, XmATTACH_NONE,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		NULL);
	ui_modid = labeled_text("text", f, 4, "UI Module Id:");
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form2,
		XmNtopAttachment, XmATTACH_NONE,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		NULL);
	since_time = labeled_text("text", f, 16, "Since:");
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form2,
		XmNtopAttachment, XmATTACH_NONE,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		NULL);
	server_status = labeled_text("text", f, 16, "Status:");
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form2,
		XmNtopAttachment, XmATTACH_NONE,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		NULL);
	server_host = labeled_text("text", f, 16, "Host:");
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form2,
		XmNtopAttachment, XmATTACH_NONE,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		NULL);
	queue_text = labeled_text("text", f, 16, "Process Queue:");
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form2,
		XmNtopAttachment, XmATTACH_NONE,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		NULL);
	message_text = labeled_text("text", f, 14, "Last Msg:");
	stat_button = pbutton("pb", f, "...");
	XtVaSetValues(stat_button,
		XmNrightAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_NONE,
		XmNtopAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	XtAddCallback(stat_button, XmNactivateCallback, LogStatistics, NULL);
	XtVaSetValues(message_text,
		XmNrightAttachment, XmATTACH_WIDGET,
		XmNrightWidget, stat_button,
		NULL);
	form1 = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		topform,
		XmNleftAttachment, XmATTACH_WIDGET,
		XmNleftWidget, form2,
		XmNleftOffset, 10,
		XmNtopAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	l1 = XtVaCreateManagedWidget("label",
		xmLabelWidgetClass,
		form1,
		XmNtopAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNlabelString, (xs=X_STR("Server/IO Module Hosts")),
		XmNalignment, XmALIGNMENT_BEGINNING,
		NULL);
	XmStringFree(xs);
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form1,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_FORM,
		NULL);
	server_text = labeled_text("host", f, 16, "Selection:");
	XtVaSetValues(server_text,
		XmNeditable, True,
		XmNcursorPositionVisible, True,
		XmNshadowThickness, 2,
		XmNhighlightThickness, 2,
		NULL);
	f = XtVaCreateManagedWidget("form",
		xmFormWidgetClass,
		form1,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		NULL);
	community_text = labeled_text("communityname", f, 16, "Community:");
	XtVaSetValues(community_text,
		XmNeditable, True,
		XmNcursorPositionVisible, True,
		XmNshadowThickness, 2,
		XmNhighlightThickness, 2,
		NULL);
	server_list = XtVaCreateManagedWidget("sw",
		xmScrolledWindowWidgetClass,
		form1,
		XmNleftAttachment, XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, l1,
		XmNrightAttachment, XmATTACH_FORM,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, f,
		XmNbottomOffset, 10,
		NULL);
	server_list = XtVaCreateManagedWidget("list",
		xmListWidgetClass,
		server_list,
		XmNvisibleItemCount, 5,
		NULL);
	XtAddCallback(server_list, XmNdefaultActionCallback, SelectConnect,
		(XtPointer)0);
	XtAddCallback(server_list,XmNbrowseSelectionCallback, SelectConnect,
		(XtPointer)3);
	XtAddCallback(server_list,XmNsingleSelectionCallback, SelectConnect,
		(XtPointer)3);
	XtAddCallback(server_list,XmNextendedSelectionCallback, SelectConnect,
		(XtPointer)3);
	XtAddCallback(server_list,XmNmultipleSelectionCallback, SelectConnect,
		(XtPointer)3);

	LoadServerHostFile();
	GetHelp(serverpanel, 7, 1);
	}


/*
 *	Callback for HNMP exit.
 */
void
HNMP_open_callback(moduleid)
int	moduleid;
	{
	}


/*
 *	Callback for HNMP exit.
 */
void
HNMP_close_callback(moduleid)
int	moduleid;
	{
	if (is_connected) {
		is_connected = 0;
		CloseHNMP(0); 
		UpdateServerPanel(0, NULL, 0);
		}
	if (recon)
		StartConnect();
	else
		waiting = 0;
	}


/*
 *	Process an HNMP message.
 */
void
HNMP_Message_process(m)
Message	m;
	{
	int	type, i, req_status, hid;
	caddr_t	msgdata;
	char	*expl;
	Message	msg;
	VarBindList	var, v;

	type = GetMessageInt(m, HNMP_msg_type);
	message_count[type] ++;
	switch (type) {
	case HNMP_WELCOME:
		HNMPversion = GetMessageInt(m, HNMP_version);
		my_id = GetMessageInt(m, HNMP_to_module_id);
		ServerConnect();
		break;
	case HNMP_GOODBYE:
		server_goodbye = True;
		break;
	case HNMP_ANNOUNCE:
		if (!is_connected) break;
		/* get hnms object id */
		hid = GetMessageInt(m, HNMP_object_id);
		/* get varbindlist */
		if (!(v=(VarBindList)Message_get(m,HNMP_variables))) {
			HNMS_err("Message_get");
			return;
			}
		if (!(var=VarBindList_copylist(v))) {
			HNMS_err("VarBindList_copylist");
			return;
			}
		AnnounceObject(hid, var);
		break;
	case HNMP_DELETE:
		if (!is_connected) break;
		/* get hnms object id */
		hid = GetMessageInt(m, HNMP_object_id);
		if (hid) DeleteObject(hid);
		break;
	case HNMP_SEND_RELATIONS:
		if (!is_connected) break;
		/* get hnms object */
		hid = GetMessageInt(m, HNMP_object_id);
		/* get varbindlist */
		if (!(v=(VarBindList)Message_get(m,HNMP_variables))) {
			HNMS_err("Message_get");
			return;
			}
		if (!(var=VarBindList_copylist(v))) {
			HNMS_err("VarBindList_copylist");
			return;
			}
		SendRelation(hid, var);
		break;
	case HNMP_SEND_DATA:
		if (!is_connected) break;
		/* get hnms object */
		hid = GetMessageInt(m, HNMP_object_id);
		/* get varbindlist */
		if (!(v=(VarBindList)Message_get(m,HNMP_variables))) {
			HNMS_err("Message_get");
			return;
			}
		if (!(var=VarBindList_copylist(v))) {
			HNMS_err("VarBindList_copylist");
			return;
			}
		SendData(hid, var);
		break;
	default:
		break;
		}
	UpdateServerPanel(5, get_time(m->msg__timestamp->parm), type);
	}


/*
 *	Log HNMP errors.
 */
void
HNMS_err(msg)
char	*msg;
	{
	extern int	hnms_errno;
	extern char	*hnms_err_strs[];

	if (hnms_errno == 0) return;
	PrintToLog(serverlog, logbuf("%s: %s (errno=%d).\n",msg,
		hnms_err_strs[hnms_errno], hnms_errno));
	Beep(1);
	hnms_errno = 0;
	}


/*
 *	Initialize the HNMP.
 */
void
InitializeHNMP(arg)
char	*arg;
	{
	HNMS_init(MODULE_UI, arg);
	HNMS_process();
	}


/*
 *	Convert an ip address to a string.
 */
char *
i2s(ip)
unsigned long	ip;
	{
	struct in_addr in;

	in.s_addr = ip;
	return(inet_ntoa(in));
	}


/*
 *	Load list of possible server hosts.
 */
void
LoadServerHostFile()
	{
	FILE	*fp;
	char	*cn;
	XmString	xs;
	int	i;

	strcpy(buf, hnms_home);
	strcat(buf, SERVERFILE);
	if (!(fp = fopen(buf, "r"))) {
		PrintToLog(serverlog,
			logbuf("Unable to access server file %s.\n", buf));
		return;
		}
	i = 0;
	while (fgets(buf, BUFSIZ, fp) && (i<NSERVERS)) {
		xs = X_STR(strtok(buf, " 	"));
		if (!XmListItemExists(server_list, xs)) {
			cn = strtok(NULL, "	 \n");
			if (strlen(cn)) {
				XmListAddItemUnselected(server_list, xs, 0);
				comname[i++] = newstr(cn);
				}
			}
		XmStringFree(xs);
		}
	}


/*
 *	Print server message statistics.
 */
void
LogStatistics(widg, a1, a2)
Widget	widg;
caddr_t	a1, a2;
	{
	PrintToLog(serverlog, "Server Message Statistics:\n");
	PrintToLog(serverlog,
		logbuf("%s = %d\n", hnmp_msg_strs[HNMP_WELCOME],
		message_count[HNMP_WELCOME]));
	PrintToLog(serverlog,
		logbuf("%s = %d\n", hnmp_msg_strs[HNMP_GOODBYE],
		message_count[HNMP_GOODBYE]));
	PrintToLog(serverlog,
		logbuf("%s = %d\n", hnmp_msg_strs[HNMP_ANNOUNCE],
		message_count[HNMP_ANNOUNCE]));
	PrintToLog(serverlog,
		logbuf("%s = %d\n", hnmp_msg_strs[HNMP_DELETE],
		message_count[HNMP_DELETE]));
	PrintToLog(serverlog,
		logbuf("%s = %d\n",
		hnmp_msg_strs[HNMP_SEND_RELATIONS],
		message_count[HNMP_SEND_RELATIONS]));
	PrintToLog(serverlog,
		logbuf("%s = %d\n", hnmp_msg_strs[HNMP_SEND_DATA],
		message_count[HNMP_SEND_DATA]));
	}


/*
 *	Open an HNMP connection.
 */
int
OpenHNMP(ip)
char	*ip;
	{
	extern int	h_errno;

	struct hostent	*h;
	unsigned long	addr;
	Message		m;

	/* try to open a udp connection */
	if ((h = gethostbyname(ip)) == NULL) {
#ifdef sgi
		PrintToLog(serverlog, logbuf("%s for %s\n", hstrerror(h_errno),
			ip));
#endif
		h_errno = 0;
		return(0);
		}
	bcopy(h->h_addr_list[0], &addr, sizeof(unsigned long));
	if (HNMP_open(addr, HNMP_PORT, MODULE_SERVER) < 0) {
		HNMS_err("HNMP_open");
		return(0);
		}
	/* send a hello */
	m = Message_create(HNMP_HELLO);
	if (HNMP_Message_enqueue(m, to_id) < 0) {
		HNMS_err("HNMP_Message_enqueue");
		return(0);
		}
	return(1);
	}


/*
 *	Open the server panel.
 */
void
OpenServerPanel(widg, a1, a2)
Widget	widg;
caddr_t	a1, a2;
	{
	OpenViewPanel(NULL, serverpanel, NULL);
	if (flashing) {
		flashing = 0;
		StopFlash(serverpanel->button, 0, SERVBLK_PIXMAP);
		}
	}


/*
 *	Save the server panel configuration.
 */
void
SaveServerPanel()
	{
	if (server_name)
		PutConfiguration("server", "host", server_name, 2);
	if (community_name)
		PutConfiguration("server", "community", community_name, 2);
	}


/*
 *	Select a connect panel option.
 */
void
SelectConnect(widg, client_data, lcs)
Widget	widg;
int	client_data;
XmListCallbackStruct	*lcs;
	{
	switch (client_data) {
	case 0:
		closeme = 1;
	/* Start the connect procedure with one server selection. */
	case 1:
		recon = 1;
		StartConnect();
		break;
	/* Disconnect from the server. */
	case 2:
		closeme = 0;
		recon = 0;
		CancelConnect();
		break;
	/* User selected a server host. */
	case 3:
		XtVaSetValues(server_text,
			XmNvalue, exstr(lcs->item),
			NULL);
		XmTextSetString(community_text, comname[lcs->item_position-1]);
		break;
	default:;
		}
	}


/*
 *	Server connected.
 */
void
ServerConnect()
	{
	if (closeme) {
		closeme = 0;
		CloseViewPanel(NULL, serverpanel, NULL);
		}
	if (is_connected) {
		bzero(message_count, NMESGTYPES*sizeof(int));
		message_count[HNMP_WELCOME] = 1;
		PrintToLog(serverlog, "Missing goodbye message.\n");
		UpdateServerPanel(0, NULL, 0);
		}
	is_connected = 1;
	waiting = 0;
	trying = 0;
	XtSetSensitive(server_list, 1);
	XtSetSensitive(connect_button, 0);
	XtSetSensitive(server_text, 1);
	XtSetSensitive(community_text, 1);
	XmListDeselectAllItems(server_list);
	if (server_name) XtFree(server_name);
	server_name = XmTextGetString(server_text);
	sprintf(buf, "%d", my_id);
	XmTextSetString(ui_modid, buf);
	UpdateServerPanel(4, server_name, 0);
	XmUpdateDisplay(serverpanel->viewform);
	}


/*
 *	Process any input from the server.
 */
void
ServerEvent()
	{
	HNMS_process();
	if (waiting) TryConnect();
	}


/*
 *	Set the process queue count display.
 */
void
SetQueueCount(k)
int	k;
	{
	char	s[32];

	sprintf(s, "%d", k);
	XmTextSetString(queue_text, s);
	}


/*
 *	Start server connect procedure.
 */
void
StartConnect()
	{
	bzero(message_count, NMESGTYPES*sizeof(int));
	XtSetSensitive(server_list, 0);
	XtSetSensitive(server_text, 0);
	XtSetSensitive(community_text, 0);
	XtSetSensitive(connect_button, 0);
	XmTextSetString(message_text, "");
	XmTextSetString(queue_text, "");
	if (host_name) XtFree(host_name);
	host_name = XmTextGetString(server_text);
	if (!strlen(host_name)) return;
	if (community_name) XtFree(community_name);
	community_name = XmTextGetString(community_text);
	if (!strlen(community_name)) community_name = NULL;
	if (!community_name) {
		PrintToLog(serverlog,
			logbuf("No community name for server host %s.\n",
			host_name));
		return;
		}
	waiting = 1;
	}


/*
 *	Set an object subscription list.
 */
void
SubHNMPData(hid, vbl)
int	hid;
VarBindList	vbl;
	{
	Message	msg;

	if (!is_connected) return;
	msg = Message_create(HNMP_SUB_DATA);
	Message_set(msg, HNMP_object_id, &hid);
	Message_set(msg, HNMP_variables, vbl);
	HNMP_Message_enqueue(msg, to_id);
	}


/*
 *	Set an object subscription list.
 */
void
SubHNMPRelations(hid, vbl)
int	hid;
VarBindList	vbl;
	{
	Message	msg;

	if (!is_connected) return;
	msg = Message_create(HNMP_SUB_RELATIONS);
	Message_set(msg, HNMP_object_id, &hid);
	Message_set(msg, HNMP_variables, vbl);
	HNMP_Message_enqueue(msg, to_id);
	}


/*
 *	Attempt a connection to the server.
 */
void
TryConnect()
	{
	waiting --;
	if (waiting) return;
	if (trying) HNMP_close(0);
	trying = 0;
	strcpy(com_name_env, "HNMS_COMMUNITY=");
	strcat(com_name_env, community_name);
	putenv(com_name_env);
	if (!OpenHNMP(host_name)) {
		CancelConnect();
		return;
		}
	waiting = WAITFOR;
	trying = 1;
	UpdateServerPanel(1, host_name, 0);
	}


/*
 *	Unset an object subscription list.
 */
void
UnsubHNMPData(hid)
int	hid;
	{
	Message	msg;

	if (!is_connected) return;
	msg = Message_create(HNMP_UNSUB_DATA);
	Message_set(msg, HNMP_object_id, &hid);
	HNMP_Message_enqueue(msg, to_id);
	}


/*
 *	Unset an object subscription list.
 */
void
UnsubHNMPRelations(hid)
int	hid;
	{
	Message	msg;

	if (!is_connected) return;
	msg = Message_create(HNMP_UNSUB_DATA);
	Message_set(msg, HNMP_object_id, &hid);
	HNMP_Message_enqueue(msg, to_id);
	}


/*
 *	Update panel to current status of server.
 */
void
UpdateServerPanel(status, s, type)
int	status;
char	*s;
int	type;
	{
	char	*t;
	XmString	xs;

	t = get_time(0);
	switch (status) {
	/* Server disconnected. */
	case 0:
		SetWorkProc();
		if (server_goodbye) {
			PrintToLog(serverlog,
				logbuf("Server disconnected at %s.\n", t));
			server_goodbye = False;
			}
		else
			PrintToLog(serverlog,
				logbuf("HNMP disconnected at %s.\n", t));
		XmTextSetString(server_status, "UnReachable");
		XmTextSetString(since_time, t);
		DestroyFlashes();
		ClearObjectListPanel();
		SetCurrentObject(NULL);
		ClearViews();
		DestroyObjects();
		StartFlash(serverpanel->button, SERVBLK_PIXMAP, SERVRED_PIXMAP,
			1);
		flashing = 1;
		Beep(4);
		break;
	/* Tryng to connect to server. */
	case 1:
		XmTextSetString(server_host, s);
		XmTextSetString(server_status, "Trying");
		XmTextSetString(since_time, t);
		break;
	/* Connection attempt canceled */
	case 2:
		XmTextSetString(server_status, "Disconnected");
		XtVaSetValues(server_time,
			XmNlabelString, (xs=X_STR("Disconnected")),
			NULL);
		XmStringFree(xs);
		XmTextSetString(since_time, t);
		XmUpdateDisplay(server_status);
		if (flashing) {
			StopFlash(serverpanel->button, 0, SERVBLK_PIXMAP);
			flashing = 0;
			}
		break;
	/* UI disconnected from server. */
	case 3:
		SetWorkProc();
		CloseHNMP(1); 
		PrintToLog(serverlog,
			logbuf("UI disconnected at %s.\n", t));
		XmTextSetString(server_status, "Disconnected");
		XmTextSetString(since_time, t);
		XtVaSetValues(server_time,
			XmNlabelString, (xs=X_STR("Disconnected")),
			NULL);
		XmStringFree(xs);
		DestroyFlashes();
		WidgetPixmap(serverpanel->button, SERVBLK_PIXMAP);
		ClearObjectListPanel();
		SetCurrentObject(NULL);
		ClearViews();
		DestroyObjects();
		break;
	/* Server connected. */
	case 4:
		PrintToLog(serverlog, logbuf("Server connected at %s.\n", t));
		XmTextSetString(server_status, "Connected");
		XmTextSetString(since_time, t);
		if (flashing) {
			StopFlash(serverpanel->button, 0, SERVGRE_PIXMAP);
			flashing = 0;
			}
		else
			WidgetPixmap(serverpanel->button, SERVGRE_PIXMAP);
		XtVaSetValues(server_label,
			XmNlabelString, (xs=X_STR(s)),
			NULL);
		XmStringFree(xs);
		XtVaSetValues(server_time,
			XmNlabelString, (xs=X_STR(t)),
			NULL);
		XmStringFree(xs);
		break;
	/* Time of last update */
	case 5:
		XmTextSetString(update_face, s);
		XmTextSetString(message_text, (char*)hnmp_msg_strs[type]);
		break;
	default:;
		}
	}
