/******************************************************************************
 * Toolkit for building distributed control systems or any other distributed system.
 *
 * Copyright (c) 1990-2005 by European Synchrotron Radiation Facility,
 *                            Grenoble, France
 *
 * 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
 *
 * File:	greta_cb.c
 *
 * Description:	The module which contains all the entry points for callbacks
 *
 * Project       :  GRETA application
 *
 * Author(s):	Builder Xcessory then completed by Elsa Simard and F. Poncet
 *              $Author: jkrueger1 $
 *
 * Original      :  October 1996
 *
 * Version:     $Revision: 1.5 $
 *
 * Date:        $Date: 2008/04/06 09:07:38 $
 *
 */

/*
 * README: This file is appended to at file generation time.
 * Edits can be made throughout the file
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

/*
 * Generated by the ICS Builder Xcessory (BX).
 *
 * Builder Xcessory 4.0
 * Code Generator Xcessory 2.0 (09/09/96)
 *
 */
 
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/List.h>
#include <Xm/ToggleB.h>

#include <X11/Xutil.h>
#include <X11/keysymdef.h>

/*
 * Standard includes for builtins.
 */
 
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include <API.h>
#include <DevServer.h>

#include <Starter.h>

/*
 * Macros to make code look nicer between ANSI and K&R.
 */
#ifndef ARGLIST
#if (NeedFunctionPrototypes == 0)
#define PROTOTYPE(p)	()
#define ARGLIST(p)	p
#define ARG(a, b)	a b;
#define GRA(a, b)	a b;
#define UARG(a, b)      a b;
#define GRAU(a, b)      a b;
#else
#define PROTOTYPE(p)	p
#define ARGLIST(p)	(
#define ARG(a, b)	a b,
#define GRA(a, b)	a b)
#ifdef __cplusplus
#define UARG(a, b)      a,
#define GRAU(a, b)      a)
#else
#define UARG(a, b)      a b,
#define GRAU(a, b)      a b)
#endif
#endif
#endif

Widget		BxFindTopShell PROTOTYPE((Widget));
WidgetList	BxWidgetIdsFromNames PROTOTYPE((Widget, char*, char*));
void 		SET_BACKGROUND_COLOR();
long 		file_concat(char *source_file_name,char *dest_file_name);

 
#include <greta.h>
#include <private/ApiP.h>

/* Global variables */

static XtCallbackRec   	*FileSelOkCbList;
static char            	entered_passwd[101];
int 			device_to_delete;
int 			server_to_delete;
int 			server_to_unreg;
int 			device_to_update;
int 			server_to_update;
int 			respool_to_update;
int			device_to_restart;
int			server_to_restart;
int 			dev_dc_flag;
Widget 			widgtab[WidgetIDsNb];

/* Some global variables defined else where */

extern dev_window *dev_tab[TAB_SIZE];
extern serv_window *serv_tab[TAB_SIZE];
extern res_window *gr_res_tab[TAB_SIZE];
extern dev_window_dc *dev_dc_tab[TAB_SIZE];

/* Some variables global to this file */

static long booloptab[bool_opIDsNb];
static char *print_a2ps_options;
static char *print_lp_options;
static d_filter dev_filter;
static char *version_lb;
static XmTextPosition last_cursor_position;
static long pid;
static ResFilterField res_filter[3];
static ds_class serv_filter;
static char *last_state;
static struct timeval ds_tout = {3,0};

/* Local function declaration */

void DevSelOK(Widget,XtPointer,XtPointer);
void DevDcSelOK(Widget,XtPointer,XtPointer);
void devping(char *, Widget, Widget);



/********** Predefined BX callback functions used by greta (begin) **********/


/*      Function Name: 	BxManageCB
 *
 *      Description:   	Given a string of the form:
 *		       	"(WL)[widgetName, widgetName, ...]"
 *			BxManageCB attempts to convert the name to a Widget
 *			ID and manage the widget.
 *
 *      Arguments:     	Widget	    w:      the widget activating the callback.
 *		       	XtPointer   client: the list of widget names to attempt
 *					    to find and manage.
 *		       	XtPointer   call:   the call data (unused).
 *
 *      Notes:        *	This function expects that there is an application
 *		       	shell from which all other widgets are descended.
 */

/* ARGSUSED */
void
BxManageCB ARGLIST((w, client, call))
ARG( Widget, w)
ARG( XtPointer, client)
GRAU( XtPointer, call)
{
    WidgetList		widgets;
    int			i;

    /*
     * This function returns a NULL terminated WidgetList.  The memory for
     * the list needs to be freed when it is no longer needed.
     */
    widgets = BxWidgetIdsFromNames(w, "BxManageCB", (String)client);

    i = 0;
    while( widgets && widgets[i] != NULL )
    {
	XtManageChild(widgets[i]);
	i++;
    }
    XtFree((char *)widgets);
}


/*      Function Name: 	BxUnmanageCB
 *
 *      Description:   	Given a string of the form:
 *		       	"(WL)[widgetName, widgetName, ...]"
 *			BxUnmanageCB attempts to convert the name to a Widget
 *			ID and unmanage the widget.
 *
 *      Arguments:     	Widget	    w:      the widget activating the callback.
 *		       	XtPointer   client: the list of widget names to attempt
 *					    to find and unmanage.
 *		       	XtPointer   call:   the call data (unused).
 *
 *      Notes:        *	This function expects that there is an application
 *		       	shell from which all other widgets are descended.
 */

/* ARGSUSED */
void
BxUnmanageCB ARGLIST((w, client, call))
ARG( Widget, w)
ARG( XtPointer, client)
GRAU( XtPointer, call)
{
    WidgetList		widgets;
    int			i;

    /*
     * This function returns a NULL terminated WidgetList.  The memory for
     * the list needs to be freed when it is no longer needed.
     */
    widgets = BxWidgetIdsFromNames(w, "BxUnmanageCB", (String)client);

    i = 0;
    while( widgets && widgets[i] != NULL )
    {
	XtUnmanageChild(widgets[i]);
	i++;
    }
    XtFree((char *)widgets);
}



/********** Predefined BX callback functions used by greta (end) **********/





/*  artifice pour forcer l'unite de couleurs de la menubar
 *			avec son ExitPB,  malgre le bug HP VUE.
 */

void file_button_cb( Widget w, XtPointer client_data, XtPointer call_data)
{
 Arg args[10];	  
 Cardinal argcnt;
 Pixel  bg;
    
    XtVaGetValues(w, XmNbackground, &bg, NULL);
    argcnt = 0;
    XtSetArg(args[argcnt], XmNbackground, bg); argcnt++;
    SET_BACKGROUND_COLOR(XtParent(w), args, &argcnt, bg);
    XtSetValues(XtParent(w), args, argcnt);
}


void
ServSelOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *info_str, *devs_str, *reso_str, *serv_name, tmp[256], *s, *strerr;
 	char file[48];
 	Widget topLevelShell, mainWindow;
 	device **devtpl_tbl;
 	int devtpl_nb, index, i, error_code;
	db_svcinfo_call info,info_all;
	DevLong error;
	char *tmp1;
	unsigned int diff;
	char ds_name[DS_NAME_LENGTH];
	char pers_name[DSPERS_NAME_LENGTH];
	long all_ds;
	long class_res;
	char **res_class1,**res_class2;
	long num_res_class1,num_res_class2,num_res_class;
	long l1,l2;
	char *text_class1,*text_class2;
	char *text_class;
	char dev_class[DEV_NAME_LENGTH];
	db_devinfo_call d_info;

    	xsSetCursor(widgtab[ServSelFormID], XC_watch);    
    	XFlush(XtDisplay(w));    

	all_ds = booloptab[servdisplay_embedded];
	class_res = booloptab[servdisplay_classresID];
	        
/* Verify that there is a server structure index available */

	if ((index=new_serv_index()) < 0)
	{
		OpenMsgBox(widgtab[ErrorBoxID]," No more server window available ");
		xsUnsetCursor(widgtab[ServSelFormID]);
	    	XFlush(XtDisplay(w));    
		return ;
	}

/* Fetch the Server Selection Text Field content and fill serv_name with it */

 	serv_name=XmTextFieldGetString(widgtab[ServSelectionTFID]); 	

/* Split full DS name in server name and personal name */

	if ((tmp1 = strchr(serv_name,'/')) == NULL)
	{
		XtFree(serv_name);
		free_serv_index(index);
		OpenMsgBox(widgtab[ErrorBoxID],"Wrong device server name syntax");
		xsUnsetCursor(widgtab[ServSelFormID]);
	    	XFlush(XtDisplay(w));    
		return ;
	}
	diff = (unsigned int)(tmp1++ - serv_name);
	strncpy(ds_name,serv_name,diff);
	ds_name[diff] = '\0';
	
	strcpy(pers_name,tmp1);
		
/* Get server information from database */

	if (db_servinfo(ds_name,pers_name,&info,&error))
	{
		strerr = dev_error_str(error);
		XtFree(serv_name);
		free_serv_index(index);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		xsUnsetCursor(widgtab[ServSelFormID]);
	    	XFlush(XtDisplay(w));    
		return;
	}
	
	if (all_ds == True)
	{
		if ((strcmp(info.process_name,ds_name) != 0) &&
		    (strcmp(info.process_name,"unknown") != 0))
		{
			if (db_servinfo(info.process_name,pers_name,&info_all,&error))
			{
				strerr = dev_error_str(error);
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID], strerr);
				free(strerr);
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
			for (i = 0;i < info.embedded_server_nb;i++)
				free(info.server[i].device);
			info = info_all;			
		}		
	}

/* Compute device number */

	devtpl_nb = 0;
	for (i = 0;i < info.embedded_server_nb;i++)
	{
		if (all_ds == True)
		{
			devtpl_nb += info.server[i].device_nb;
		}
		else
		{
			if (strcmp(ds_name,info.server[i].server_name) == 0)
			{
				devtpl_nb += info.server[i].device_nb;
			}
		}
	}
	
	if (devtpl_nb == 0)
	{
		sprintf(tmp,"No device defined for server %s !",serv_name);
		OpenMsgBox(widgtab[ErrorBoxID],tmp);
		XtFree(serv_name);
		free_serv_index(index);
		for (i = 0;i < info.embedded_server_nb;i++)
			free(info.server[i].device);
		free(info.server);
		xsUnsetCursor(widgtab[ServSelFormID]);
	    	XFlush(XtDisplay(w));    
		return ;
	}

/* If the class resource option is ON, get these resources */

	if (class_res == True)
	{
		if (db_getresresoval("class",ds_name,"*","*",&num_res_class1,
				     &res_class1,&error))
		{
			strerr = dev_error_str(error);
			XtFree(serv_name);
			free_serv_index(index);
			OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
			for (i = 0;i < info.embedded_server_nb;i++)
				free(info.server[i].device);
			free(info.server);
			xsUnsetCursor(widgtab[ServSelFormID]);
	    		XFlush(XtDisplay(w));    
			return;
		}

/* Get device class */

		for (i = 0;i < info.embedded_server_nb;i++)
		{
			if (strcmp(info.server[i].server_name,ds_name) == 0)
			{
				strcpy(dev_class,info.server[i].device[0].dev_name);
			}
		}
		
		if (db_deviceinfo(dev_class,&d_info,&error))
		{
			strerr = dev_error_str(error);
			XtFree(serv_name);
			free_serv_index(index);
			OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
			for (i = 0;i < info.embedded_server_nb;i++)
				free(info.server[i].device);
			free(info.server);
			for (i = 0;i < num_res_class1;i++)
				free(res_class1[i]);
			free(res_class1);
			xsUnsetCursor(widgtab[ServSelFormID]);
	    		XFlush(XtDisplay(w));    
			return;
		}		

		if (strcmp(d_info.device_class,"unknown") != 0)
		{				
			if (db_getresresoval("class",d_info.device_class,"*",
					     "*",&num_res_class2,
				     	     &res_class2,&error))
			{
				strerr = dev_error_str(error);
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID], strerr);
				free(strerr);
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				free(info.server);
				for (i = 0;i < num_res_class1;i++)
					free(res_class1[i]);
				free(res_class1);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
		}
		
/* Build motif string from these resources */

		if (num_res_class1 != 0)
		{
			if (xsCreateStringForText(res_class1,num_res_class1,
						  &text_class1))
			{
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				free(info.server);
				for (i = 0;i < num_res_class1;i++)
					free(res_class1[i]);
				free(res_class1);
				for (i = 0;i < num_res_class2;i++)
					free(res_class2[i]);
				free(res_class2);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
		}
		
		if (num_res_class2 != 0)
		{
			if (xsCreateStringForText(res_class2,num_res_class2,
						  &text_class2))
			{
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				free(info.server);
				for (i = 0;i < num_res_class1;i++)
					free(res_class1[i]);
				free(res_class1);
				for (i = 0;i < num_res_class2;i++)
					free(res_class2[i]);
				free(res_class2);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
		}
		
/* Concat the two strings */

		if ((num_res_class1 != 0) && (num_res_class2 != 0))
		{
			l1 = strlen(text_class1);
			l2 = strlen(text_class2);
			
			if ((text_class = (char *)malloc(l1 + l2 + 2)) == NULL)
			{
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				free(info.server);
				for (i = 0;i < num_res_class1;i++)
					free(res_class1[i]);
				free(res_class1);
				for (i = 0;i < num_res_class2;i++)
					free(res_class2[i]);
				free(res_class2);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
			
			strcpy(text_class,text_class1);
			strcat(text_class,text_class2);
			
			free(text_class1);
			free(text_class2);
			for (i = 0;i < num_res_class1;i++)
				free(res_class1[i]);
			free(res_class1);
			for (i = 0;i < num_res_class2;i++)
				free(res_class2[i]);
			free(res_class2);
		}
		else if (num_res_class1 != 0)
		{
			l1 = strlen(text_class1);
			
			if ((text_class = (char *)malloc(l1 + 2)) == NULL)
			{
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				free(info.server);
				for (i = 0;i < num_res_class1;i++)
					free(res_class1[i]);
				free(res_class1);
				for (i = 0;i < num_res_class2;i++)
					free(res_class2[i]);
				free(res_class2);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
			
			strcpy(text_class,text_class1);
			
			free(text_class1);
			for (i = 0;i < num_res_class1;i++)
				free(res_class1[i]);
			free(res_class1);
		}
		else if (num_res_class2 != 0)
		{
			l2 = strlen(text_class2);
			
			if ((text_class = (char *)malloc(l2 + 2)) == NULL)
			{
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				free(info.server);
				for (i = 0;i < num_res_class1;i++)
					free(res_class1[i]);
				free(res_class1);
				for (i = 0;i < num_res_class2;i++)
					free(res_class2[i]);
				free(res_class2);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
			
			strcat(text_class,text_class2);
			
			free(text_class2);
			for (i = 0;i < num_res_class2;i++)
				free(res_class2[i]);
			free(res_class2);
		}
			
		num_res_class = num_res_class1 + num_res_class2;
		
	}
	
/* Get resources for all server devices */

	if (db_getserverdeviceres(ds_name,pers_name,&info,&reso_str,devtpl_nb,all_ds,&error))
	{
		strerr = dev_error_str(error);
		XtFree(serv_name);
		free_serv_index(index);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		for (i = 0;i < info.embedded_server_nb;i++)
			free(info.server[i].device);
		free(info.server);
		if (num_res_class != 0)
			free(text_class);
		xsUnsetCursor(widgtab[ServSelFormID]);
	    	XFlush(XtDisplay(w));    
		return;
	}

/* Build the server device list string */

	if (db_builddevicelist(ds_name,pers_name,&info,&devs_str,all_ds,&error))
	{
		strerr = dev_error_str(error);
		XtFree(serv_name);
		free_serv_index(index);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		for (i = 0;i < info.embedded_server_nb;i++)
			free(info.server[i].device);
		free(info.server);
		if (reso_str != NULL)
			free(reso_str);
		if (num_res_class != 0)
			free(text_class);
		xsUnsetCursor(widgtab[ServSelFormID]);
	    	XFlush(XtDisplay(w));    
		return;
	}

/* Build the servinfo result string */

	if (db_buildservinfo(ds_name,pers_name,&info,&info_str,all_ds,&error))
	{
		strerr = dev_error_str(error);
		XtFree(serv_name);
		free_serv_index(index);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		for (i = 0;i < info.embedded_server_nb;i++)
			free(info.server[i].device);
		free(info.server);
		if (reso_str != NULL)
			free(reso_str);
		free(devs_str);
		if (num_res_class != 0)
			free(text_class);
		xsUnsetCursor(widgtab[ServSelFormID]);
	    	XFlush(XtDisplay(w));    
		return;
	}
				
/* Position topLevelShell and mainWindow to pass them to xsServerWindowCreate() */

	mainWindow=XtParent(XtParent(widgtab[ServSelFormID])); 
	topLevelShell=XtParent(mainWindow);
	  
/* Create the window */

	xsServerWindowCreate(topLevelShell, mainWindow, index, serv_name);
	XtFree(serv_name);

/* If some classes resources have been retrieved, concatenate them with
   devices resources */
   
	if (class_res == True)
	{
		if (num_res_class != 0)
		{
			l1 = strlen(text_class);
			if (reso_str != NULL)
				l2 = strlen(reso_str);
			else
				l2 = 0;
		
			if ((text_class = realloc(text_class,l1 + l2 + 2)) == NULL)
			{
				XtFree(serv_name);
				free_serv_index(index);
				OpenMsgBox(widgtab[ErrorBoxID], strerr);
				for (i = 0;i < info.embedded_server_nb;i++)
					free(info.server[i].device);
				free(info.server);
				if (reso_str != NULL)
					free(reso_str);
				free(devs_str);
				if (num_res_class != 0)
					free(text_class);
				xsUnsetCursor(widgtab[ServSelFormID]);
	    			XFlush(XtDisplay(w));    
				return;
			}
			strcat(text_class,"\n");
			if (reso_str != NULL)
			{
				strcat(text_class,reso_str);
				free(reso_str);
				reso_str = text_class;
			}
			else
				reso_str = text_class;
		}
	}

/* Copy some interesting info into the server structure */

	serv_tab[index]->pid = info.pid;
	serv_tab[index]->pn = info.program_num;
	if (strcmp(info.process_name,"unknown") != 0)
		strcpy(serv_tab[index]->proc_name,info.process_name);
	if (strcmp(info.host_name,"not_exp") != 0)
		strcpy(serv_tab[index]->host_name,info.host_name);
	strcpy(serv_tab[index]->pers_name,pers_name);
	
	if (pid == 0)
		serv_tab[index]->restart = False;
	else
		serv_tab[index]->restart = True;
			
/* Fill the text widgets */

	XmTextSetString(serv_tab[index]->infotext, info_str);
	XmTextSetString(serv_tab[index]->devstext, devs_str);
	if (reso_str != NULL)
		XmTextSetString(serv_tab[index]->resotext, reso_str);

/* Upkeep of a reference resource file for Update, set the file name field */

	sprintf(file, "/tmp/greta%d_serv%d.res", pid, index);
	strcpy(serv_tab[index]->file, file);
	serv_tab[index]->serv_save_pathname=NULL;
	if (reso_str != NULL)
		l2 = strlen(reso_str);
	else
		l2 = 0; 
	devs_str=(char *)realloc(devs_str,(strlen(devs_str)+l2+1)*sizeof(char));
	if (reso_str != NULL)
		strcat(devs_str, reso_str);
	file_create(file, devs_str);

/* Register the texts states to initialize the Undo fonctionality */

	save_text(index);
	
/* Manage the server window */

	XtManageChild(serv_tab[index]->window);
	xsUnsetCursor(widgtab[ServSelFormID]);
    	XFlush(XtDisplay(w));
	
/* Free memory */

	for (i = 0;i < info.embedded_server_nb;i++)
		free(info.server[i].device);
	free(info.server);
	if (reso_str != NULL)
		free(reso_str);
	free(devs_str);
	free(info_str);      	
}



void ServUnregCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	char title[256];

    	int ind=(int)client_data;
    
	server_to_unreg=ind;
	sprintf(title, "Unregister %",serv_tab[ind]->servname); 
	xsSetTitle(widgtab[ServUnregBoxID], title);
	XtManageChild(widgtab[ServUnregBoxID]);
	
}



void ServUndoCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 Display *display;
 Widget dest;
 serv_status serv_tmp;
    int ind=(int)client_data;

/* Set dest to which editable text has to be undo . (devstext or resotext) */
	
	display=XtDisplay(serv_tab[ind]->window);
	dest=XmGetDestination(display);
	
/* CASE OF DEVSTEXT */

	if (dest==serv_tab[ind]->devstext)
	{
/* Upkeep of the current status = next last_state in a temporary */

		serv_tmp.devs=XmTextGetString(serv_tab[ind]->devstext);
		serv_tmp.devspos= XmTextGetInsertionPosition(serv_tab[ind]->devstext);

/* Restore the current last_state= update the current status */

		XmTextSetString(serv_tab[ind]->devstext,serv_tab[ind]->last_state.devs);
		XmTextSetInsertionPosition(serv_tab[ind]->devstext,serv_tab[ind]->last_state.devspos);

/* Update last_state from the temporary */

		XtFree(serv_tab[ind]->last_state.devs);
		serv_tab[ind]->last_state.devs=serv_tmp.devs;
		serv_tab[ind]->last_state.devspos=serv_tmp.devspos;
	}

/* CASE OF RESOTEXT */

	else if (dest==serv_tab[ind]->resotext)
	{
/* Upkeep of the current status = next last_state in a temporary */
		serv_tmp.reso=XmTextGetString(serv_tab[ind]->resotext);
		serv_tmp.resopos= XmTextGetInsertionPosition(serv_tab[ind]->resotext);

/* Restore the current last_state= update the current status */
		XmTextSetString(serv_tab[ind]->resotext,
					serv_tab[ind]->last_state.reso);
		XmTextSetInsertionPosition(serv_tab[ind]->resotext,
					serv_tab[ind]->last_state.resopos);

/* Update last_state from the temporary */
		XtFree(serv_tab[ind]->last_state.reso);
		serv_tab[ind]->last_state.reso=serv_tmp.reso;
		serv_tab[ind]->last_state.resopos=serv_tmp.resopos;
	}
	
/* OTHERS CASES NOTHING HAPPENS */
}



void ServSaveCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   char   *save_file, *reso_text, *tmp, msg_str[1001];
   int    ind=(int)client_data;

   if (serv_tab[ind]->serv_save_pathname == NULL)
      return;
   
   save_file = serv_tab[ind]->serv_save_pathname;

   /* Copy resource and devlist windows contents into file */
		
   reso_text=XmTextGetString(serv_tab[ind]->devstext);
   tmp=XmTextGetString(serv_tab[ind]->resotext);
   reso_text=(char *)realloc(reso_text,
                             (strlen(reso_text)+strlen(tmp)+1)*sizeof(char));
   strcat(reso_text, tmp);
   XtFree(tmp);
   if (file_create(save_file, reso_text) == -1)
   {
	XtFree(reso_text);
	sprintf(msg_str,"Can't open file %s",save_file);
	OpenMsgBox(widgtab[ErrorBoxID], msg_str);
	return;
   }
   XtFree(reso_text);
   sprintf(msg_str,
           "the devices list and resources texts of %s \n\
            has been saved as displayed into :\n%s",
            serv_tab[ind]->servname, save_file);

   OpenMsgBox(widgtab[InfoBoxID], msg_str);

}




int next(int ResListID)
{
	switch(ResListID)
	{
	case ResDomListID : return ResFamListID; break;
	case ResFamListID : return ResMembListID; break;
	case ResMembListID : return ResNameListID; break;
	default : return -1; break;
	}
}



void ResClickCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 char filter_text[256], s[256];
 XmString xmstr;
 int i, k, *pos_list, pos_cnt;
 int client_list=(int)client_data;

	strcpy(filter_text, "");
    k=0;
/* Treatment of the list widgets preceding the client :
   reselect the right element according to memorized filter res_filter if it is
   not empty, and construct the filter string that will be displayed . */
	for(i=ResDomListID; i!=client_list; i=next(i))
	{
		/* If an element has been memorized for this field, reselect it */
		if (strcmp(res_filter[k], ""))
		{
			xmstr=XmStringCreateLocalized(res_filter[k]);
			XmListSelectItem(widgtab[i], xmstr , False);
			XmStringFree(xmstr);
		}
		/* If no memorized element for this field 
			1) no element selected at all : select the first one
			2) else leave the selection as is
		 */
		else if (!XmListGetSelectedPos(widgtab[i], &pos_list, &pos_cnt))
		{
			XmListSelectPos(widgtab[i], 1, False);
		}
		
		/* Add to the to-be-displayed filter string the selected elt plus '/'
		   */
		sprintf(filter_text, "%s%s/", 
				filter_text, xsListGetBrowseSelection(widgtab[i]));
		k++;
	}

/* k points to the res_filter elt corresponding to client list */
/* Treatment for client_list=i */
/* Terminate and display in TextField the new filter string */
	sprintf(filter_text, "%s%s", 
			filter_text,xsListGetBrowseSelection(widgtab[client_list]));
	/* If it's not the name list (there is still another field waited for),
	   append '/' */
	if(i!=ResNameListID) strcat(filter_text, "/");
	xsTextFieldSetString(widgtab[ResFilterTFID],filter_text);

/* Treatment of the list immediately following the client one, if existing 
	1) if the content doesn't result from a filtration 
	   then clear the list and add the joker "*" elt (except
	   for the fam list).
	2) deselect anyway 
 */
/* k points to the res_filter elt corresponding to client list=list preceding
   the to-be-treated one */
	if ((i=next(i))!= -1)
	{
		if (!strcmp(res_filter[k], ""))
		{
			XmListDeleteAllItems(widgtab[i]);
			if (i!=ResFamListID)
			{
				xmstr=XmStringCreateLocalized("*");
				XmListAddItem(widgtab[i], xmstr, 0);
				XmStringFree(xmstr);
			}
		}
		else XmListDeselectAllItems(widgtab[i]);
		k++;	
	}
	
/* Treatment of the remaining lists :
	1) if the content doesn't result from a filtration (empty list or
	reduced-to-"*" list) then clear the list .
	2) deselect anyway 
 */
	while((i=next(i))!= -1)
	{
		if (!strcmp(res_filter[k], ""))
			XmListDeleteAllItems(widgtab[i]);
		else XmListDeselectAllItems(widgtab[i]);
		k++;	
	}
}




void ResFilterCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *strfilter, *ptr, *rem, s[256];
 	ResFilterField cur_filter[3];
 	int charsize, i, maxind, cur_listID, pos;
 	XmString xmstr, *xmstr_tbl;
 	char dom[20];
 	char **resu_tbl;
	long resu,resu_nb;
	DevLong error;
	char *strerr;
 
    	xsSetCursor(widgtab[ResSelFormID], XC_watch);
    	XFlush(XtDisplay(w));
    	charsize=sizeof(char);

/* Decomposition of the string displayed in ResFilterTF, initialization of
   cur_filter and syntaxic tests */    

 	strfilter=XmTextFieldGetString(widgtab[ResFilterTFID]);
 	
 	if ((ptr=strchr(strfilter, '/'))==NULL)
 	{
 		OpenMsgBox(widgtab[ErrorBoxID],
"             Syntaxic error !\n\n\
Each field of the filter should be follow by '/', \n\
and there should be at least the selected domain component .");
		free(strfilter);
		xsUnsetCursor(widgtab[ResSelFormID]);
		XFlush(XtDisplay(w));
		return;
 	}
 	ptr[0]='\0';
 	strcpy(cur_filter[0], strfilter);
 	rem=ptr+charsize;
 	
 	for(i=1;(i<3)&&((ptr=strchr(rem, '/'))!=NULL);i++)
 	{
 		ptr[0]='\0';
 		strcpy(cur_filter[i], rem);
 		rem=ptr+charsize;
 	}
	
/* If it remains something after the last '/', or after the maximum 3 components 
   have been scanned . */ 
   	
 	if (strcmp(rem, "") != 0)
 	{

 		OpenMsgBox(widgtab[ErrorBoxID],
"             Syntaxic error !\n\n\
The filter should consist of at most three fields\n\
(domain, family, member) each separated by '/',\n\
which should also end the filter .");
		free(strfilter);
		xsUnsetCursor(widgtab[ResSelFormID]);
		XFlush(XtDisplay(w));
		return;
 	}
	XtFree(strfilter);
 	maxind=i;

 /* Fill with "" the remaining fields to reinitialize . */
 
 	for (;i<3;strcpy(cur_filter[i++], ""));
 	
/* Update the lists content and selection ; semantic tests */

	cur_listID=ResDomListID;
	for (i = 0;i < maxind;i++)
	{
		xmstr=XmStringCreateLocalized(cur_filter[i]);
		pos=XmListItemPos(widgtab[cur_listID], xmstr);
		XmStringFree(xmstr);
		if (!pos)
		{
		
/* cur_filter[i] doesn't belong to cur_list */
	
 			sprintf(s,"%s isn't a possible value for the field number %d\n .", 
 					cur_filter[i], i+1);
 			OpenMsgBox(widgtab[ErrorBoxID], s);
			xsUnsetCursor(widgtab[ResSelFormID]);
			XFlush(XtDisplay(w));
			return;
		}
		
/* reposition the cur_list selection to match the filter */
	
		XmListSelectPos(widgtab[cur_listID], pos, False);
		
/* launch the appropriate database search */

		strcpy(dom, cur_filter[0]);
		switch(i)
		{
		case 0 : 
			resu = db_getresfamilylist(dom,&resu_nb,&resu_tbl,&error);
			break;
			
		case 1 : 
			resu = db_getresmemberlist(dom,cur_filter[1],&resu_nb,
						   &resu_tbl,&error);
			break;
			
		case 2 : 
			resu = db_getresresolist(dom,cur_filter[1],cur_filter[2],
						 &resu_nb,&resu_tbl,&error);
			break;
		}
		
		if(resu == -1)
		{
			strerr = dev_error_str(error);
 			OpenMsgBox(widgtab[ErrorBoxID],strerr);
			free(strerr);
			xsUnsetCursor(widgtab[ResSelFormID]);
			XFlush(XtDisplay(w));
			return;
		}
		
		if (resu_nb == 0)
		{
		
/* No solutions found */
		
 			sprintf(s,"              Semantic error !\n\n\
No resources corresponding to filter fields number 1 to %d\n .", 
 					cur_filter[i], i+1);
 			OpenMsgBox(widgtab[ErrorBoxID], s);
			xsUnsetCursor(widgtab[ResSelFormID]);
			XFlush(XtDisplay(w));
			return;
		}
		
/* Update the following list with the database search result */
	
		cur_listID=next(cur_listID);
		XmListDeleteAllItems(widgtab[cur_listID]);
		if (cur_listID!=ResFamListID)
		{

/* Put "*" that has to be the first item proposed to user's choice */

			xmstr=XmStringCreateLocalized("*");
			XmListAddItem(widgtab[cur_listID], xmstr, 0);
			XmStringFree(xmstr);
		}
		
/* Add all the items found in database at the end */

		xmstr_tbl = etxsXmStringTableCreate(resu_tbl,resu_nb);
		str_ptr_tbl_free(resu_tbl, resu_nb);
		XmListAddItems(widgtab[cur_listID], xmstr_tbl, resu_nb, 0);
		etxsXmStringTableFree(xmstr_tbl, resu_nb);
	}
	
/* cur_listID points on the last filled lists : the following lists have to be 
   cleared */
   
	while((cur_listID=next(cur_listID))!= -1)
		XmListDeleteAllItems(widgtab[cur_listID]);
	
/*
 * - The aimed list has been computed, but hasn't any default selected item .
 * - Each list before has be (re)computed end its selection (re)position to
 *   match the corresponding filter field .
 * - Each list after has been emptied .
 */
/* Happy end : updating of the memorized filter */

	for(i=0;i<3;i++)
		strcpy(res_filter[i], cur_filter[i]);
		
	xsUnsetCursor(widgtab[ResSelFormID]);
	XFlush(XtDisplay(w));
}





void ResDismissCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 char s[256];
 int ind=(int)client_data;
	
	XtUnmanageChild(gr_res_tab[ind]->window);
	XtDestroyWidget(gr_res_tab[ind]->window);
	res_remove(ind);
}




void ResUndoCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *txt_tmp;
 	XmTextPosition pos_tmp;
 
 	int ind=(int)client_data;
 
	txt_tmp=XmTextGetString(gr_res_tab[ind]->resotext);
	pos_tmp=XmTextGetInsertionPosition(gr_res_tab[ind]->resotext);
	XmTextSetString(gr_res_tab[ind]->resotext, gr_res_tab[ind]->last_state);
	XmTextSetInsertionPosition(gr_res_tab[ind]->resotext, gr_res_tab[ind]->last_position);
	XtFree(gr_res_tab[ind]->last_state);
	gr_res_tab[ind]->last_state=txt_tmp;
	gr_res_tab[ind]->last_position=pos_tmp;
}





void ResCopyCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 Time time;
 int ind=(int)client_data;
 XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;
 
	time=acs->event->xbutton.time;
	XmTextCopy(gr_res_tab[ind]->resotext, time);
}





void ServClickCb( Widget w, XtPointer client_data, XtPointer call_data)
{
  	char *s;
  	XmString xmstr = NULL;
  	int      index= (int) client_data;

	s=(char *)malloc(sizeof(ds_class)+sizeof(ds_pname)+1);
	if(index==ClassListID)
	{
		XmListDeselectAllItems(widgtab[PnameListID]);
		sprintf(s,"%s/", xsListGetBrowseSelection(widgtab[ClassListID]));
                strcat(s, "*");
	    xsTextFieldSetString(widgtab[ServFilterTFID],s);
	    xsTextFieldSetString(widgtab[ServSelectionTFID],s);
	}
	else /* index==PnameListID 
			so there is already a meaningfull filter in serv_filter */{
		xmstr=XmStringCreateLocalized(serv_filter);
		XmListSelectItem(widgtab[ClassListID],xmstr , 0);
		sprintf(s,"%s/",serv_filter);
                strcat(s, "*");
	    xsTextFieldSetString(widgtab[ServFilterTFID],s);
		sprintf(s,"%s/%s",serv_filter,
				xsListGetBrowseSelection(widgtab[PnameListID]));
		xsTextFieldSetString(widgtab[ServSelectionTFID],s);
	}
	free(s);
	if (xmstr != NULL)
		XmStringFree(xmstr);
}





void ServDelOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	unsigned int diff;
	char ds_name[DS_NAME_LENGTH];
	char pers_name[DSPERS_NAME_LENGTH];
	char *tmp;
	long flag;
	DevLong error;
	char *strerr;
	
    	xsSetCursor(XtParent(serv_tab[server_to_delete]->window), XC_watch);    
    	XFlush(XtDisplay(w));    	

/* Split full device server name */

	tmp = strchr(serv_tab[server_to_delete]->servname,'/');
	diff = (unsigned int)(tmp++ - serv_tab[server_to_delete]->servname);
	strncpy(ds_name,serv_tab[server_to_delete]->servname,diff);
	ds_name[diff] = '\0';
	
	strcpy(pers_name,tmp);
		    
/* Delete server from database */

	if (XmToggleButtonGetState(widgtab[ServDelWResTBID]))
		flag = True;
	else
		flag = False;
		
	if (db_servdelete(ds_name,pers_name,flag,&error))
	{
		strerr = dev_error_str(error);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
	}
	
	xsUnsetCursor(XtParent(serv_tab[server_to_delete]->window));
    	XFlush(XtDisplay(w));    
}





void ServPreparePrintCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    	int ind=(int)client_data;
 	FILE *stream; 
 	char txt[256], file[48];    
 	char *framed_title, *info, *devs, *res; 
	
	sprintf(file, "/tmp/greta%d.txt", pid);

/* Fill greta.txt */

	stream=fopen(file, "w");

/* Put the displayed device name as a title */

    	sprintf(txt,"Server %s",serv_tab[ind]->servname);
	framed_title=(char *)frame(txt);
	fputs(framed_title,stream);
	free(framed_title);
	
/* Get the infoText, devListText and resourceText contents */

	info=XmTextGetString(serv_tab[ind]->infotext);
	devs=XmTextGetString(serv_tab[ind]->devstext);
	res=XmTextGetString(serv_tab[ind]->resotext);
			
/* Put the info text widget content */

	sprintf(txt,"\n\nInformations :\n------------\n\n");
	fputs(txt,stream);
	fputs(info,stream);
	XtFree(info);
			
/* Put the devices list text widget content */

	sprintf(txt,"\n\nDevices list :\n------------\n\n");
	fputs(txt,stream);
	fputs(devs,stream);
	XtFree(devs);

/* Put the resources text widget content */

	sprintf(txt,"\n\nResources :\n---------\n\n");
	fputs(txt,stream);
	fputs(res,stream);
	XtFree(res);

/* Terminate */

	fclose(stream);
	sprintf(txt,"Print server %s",serv_tab[ind]->servname);
	xsSetTitle(widgtab[PrintFormID], txt);
	
}





void ServCutCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	Time time;
 	char *sel;
 
    	int ind=(int)client_data;
    	XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;

	time=acs->event->xbutton.time;
	/* Cut from resotext if it owns the primary selection, or
	   from devstext if it owns the primary selection or do nothing */
	if((sel=XmTextGetSelection(serv_tab[ind]->resotext))!=NULL)
	{
		if(!strcmp(sel, "")) return; /* don't loose primary selection and
		last_state for an action without visible effect */
		save_text(ind);
		XmTextCut(serv_tab[ind]->resotext,time);
	}
	else if((sel=XmTextGetSelection(serv_tab[ind]->devstext))!=NULL)
	{
		if(!strcmp(sel, "")) return; /* don't loose primary selection and
		last_state for an action without visible effect */
		save_text(ind);
		XmTextCut(serv_tab[ind]->devstext,time);
	}
	XtFree(sel);
}





void ServCopyCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	Time time;
 	char *sel;

    	int ind=(int)client_data;
    	XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;

	time=acs->event->xbutton.time;
/* Copy from resotext if it owns the primary selection, or
   from devstext if it owns the primary selection or do nothing */
	if((sel=XmTextGetSelection(serv_tab[ind]->resotext))!=NULL)
	{
		if(!strcmp(sel, "")) return; /* don't loose primary selection for an
		action without visible effect */
		XmTextCopy(serv_tab[ind]->resotext,time);
	}
   	else if((sel=XmTextGetSelection(serv_tab[ind]->devstext))!=NULL)
	{
		if(!strcmp(sel, "")) return; /* don't loose primary selection for an
		action without visible effect */
		XmTextCopy(serv_tab[ind]->devstext,time);
	}
	XtFree(sel);
}





void ServDeleteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *sel;

    	int ind=(int)client_data;

/* Save and delete from resotext if it owns the primary selection, or
   from devstext if it owns the primary selection or do nothing */
   
	if((sel = XmTextGetSelection(serv_tab[ind]->resotext)) != NULL)
	{
		if(!strcmp(sel, "")) return; /* don't loose primary selection and
		last_state for an action without visible effect */
		save_text(ind);
		XmTextRemove(serv_tab[ind]->resotext);
	}
	else if((sel = XmTextGetSelection(serv_tab[ind]->devstext)) != NULL)
	{
		if(!strcmp(sel, "")) return; /* don't loose primary selection and
		last_state for an action without visible effect */
		save_text(ind);
		XmTextRemove(serv_tab[ind]->devstext);
	}
	XtFree(sel);
}





void ResSelOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *res_filter, *resfilter;
 	char *error_str, *strerr;
 	char *tmp, *dom, *fam, *memb, *name;
 	int resu, index,i;
 	char **reso_str;
 	Widget topLevelShell, mainWindow;
 	char file[48];
	long num;
	DevLong error;
	char *text_str;
 
	xsSetCursor(widgtab[ResSelFormID], XC_watch);
    	XFlush(XtDisplay(w));
		
/* Pick up the string displayed in ResFilterTF, syntaxic tests */    

 	res_filter=XmTextFieldGetString(widgtab[ResFilterTFID]);
 	
/* Initialize resfilter to res_filter without blanks, and syntaxic tests :
   exactly one non empty word in each field, except for las field :
   NoBlanksFieldsStr considers as valid a filter ended by an empty field, that
   is to say by "/" followed by as many blanks as wishes . */

	if((resu=NoBlanksFieldStr(res_filter, &resfilter, &strerr)) < 0)
	{
 		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		XtFree(res_filter);
		xsUnsetCursor(widgtab[ResSelFormID]);
		XFlush(XtDisplay(w));
		return;
	}
	XtFree(res_filter);

/* Estimate error_str (generate at this level) size */

	error_str=malloc((strlen(resfilter)+256)*sizeof(char));
	
/* Verify there is the right number of fields : 3 '/' in resfilter, and none
   terminating it */

	if((resu!=3)||(resfilter[strlen(resfilter)-1]=='/'))
 	{
 		sprintf(error_str, "To constitute a valid selection, %s \n\
should follow :\n        \"domain/family/member/resource name\" .", resfilter);
 		OpenMsgBox(widgtab[ErrorBoxID], error_str);
		free(resfilter);
		free(error_str);
		xsUnsetCursor(widgtab[ResSelFormID]);
		XFlush(XtDisplay(w));
		return;
 	}
	
/* Semantic test : neither domain nor family may be generic, dom, fam and memb
   must be inferior-to-20 length, and names inferior to 24 length (reso and
   reso_long definition in db_setup.h */
   
 	tmp=strdup(resfilter);
 	dom=strtok(tmp, "/");
 	fam=strtok(NULL, "/");
 	memb=strtok(NULL, "/");
 	name=strtok(NULL, "/");
	
 	if((strlen(dom)>=20) || (strlen(fam)>=20)
 	 || (strlen(memb)>=20) || (strlen(name)>=24))
 	{
 		free(tmp);
 		sprintf(error_str, "One of the fields of %s is too big to be valid !\n\
A domain, family or member cannot exceed 20 characters,\n\
and a resource name cannot exceed 24 characters\n", resfilter);
 		OpenMsgBox(widgtab[ErrorBoxID], error_str);
		free(resfilter);
		free(error_str);
		xsUnsetCursor(widgtab[ResSelFormID]);
		XFlush(XtDisplay(w));
		return;
 	}
	
 	if (!strcmp(dom, "*") || !strcmp(fam, "*"))
 	{
 		free(tmp);
 		sprintf(error_str, "You must choose a precise value for both \n\
the domain and family fields !\n\
The joker \"*\" may replace only the member \n\
and/or name field .");
 		OpenMsgBox(widgtab[ErrorBoxID], error_str);
		free(error_str);
		free(resfilter);
		xsUnsetCursor(widgtab[ResSelFormID]);
		XFlush(XtDisplay(w));
		return;
 	}
 	
/* Check for an available resources window index */

	if ((index = new_res_index()) < 0)
	{
		OpenMsgBox(widgtab[ErrorBoxID]," No more resources window available !");
		free(error_str);
		free_res_index(index);
		free(resfilter);
		xsUnsetCursor(widgtab[ResSelFormID]);
		XFlush(XtDisplay(w));
		return;
	}

/* Search the database and thereafter formate the string composed of every 
   resource matching resfilter, consecutive errors treatment */

	if (db_getresresoval(dom,fam,memb,name,&num,&reso_str,&error))
	{
		strerr = dev_error_str(error);
		free(error_str);
		free(resfilter);
		free_res_index(index);
		OpenMsgBox(widgtab[ErrorBoxID],strerr);
		free(strerr);
		xsUnsetCursor(widgtab[ResSelFormID]);
	    	XFlush(XtDisplay(w));    
		return;
	}
	
	if(num == 0)
	{
		free_res_index(index);
		strcpy(error_str, "Invalid filter, no resources have been found");
		free(resfilter);
		OpenMsgBox(widgtab[ErrorBoxID], error_str);
		free(error_str);
		xsUnsetCursor(widgtab[ResSelFormID]);
	    	XFlush(XtDisplay(w));    
		return ;
	}

/* Create a resource string */

	if (xsCreateStringForText(reso_str,num,&text_str))
	{
		for (i = 0;i < num;i++)
			free(reso_str[i]);
		free(reso_str);
		free_res_index(index);
		strcpy(error_str, "Can't allocate memory");
		free(resfilter);
		OpenMsgBox(widgtab[ErrorBoxID], error_str);
		free(error_str);
		xsUnsetCursor(widgtab[ResSelFormID]);
	    	XFlush(XtDisplay(w));    
		return ;
	}
	   
/* Happy end */

	free(error_str);
	free(tmp);
	
/* Dynamically create the resources window and associated structures
   Position topLevelShell and mainWindow to pass them to 
   xsResourcesWindowCreate() .*/
	
	mainWindow=XtParent(XtParent(widgtab[ResSelFormID])); 
	topLevelShell=XtParent(mainWindow);
	  
/* Create the window */

	xsResourcesWindowCreate(topLevelShell, mainWindow, index, resfilter);
	free(resfilter);
	
/* Fill the text widget */
	
	XmTextSetString(gr_res_tab[index]->resotext, text_str);
	
/* Initialize last_state and last_position for Undo */

	gr_res_tab[index]->last_state=strdup(text_str);
	gr_res_tab[index]->last_position=0; 
	gr_res_tab[index]->res_save_pathname=NULL; 
	
/* Upkeep of a reference resource file for Update, set the file name field  */

	sprintf(file, "/tmp/greta%d_res%d.res", pid, index);
	strcpy(gr_res_tab[index]->file, file);
	file_create(file, text_str);
	
/* Free memory allocated by the db_getresoval function */

	for (i = 0;i < num;i++)
		free(reso_str[i]);
	free(reso_str);	
	free(text_str);

/* Manage the server window */

	XtManageChild(gr_res_tab[index]->window); 
	xsUnsetCursor(widgtab[ResSelFormID]);
	XFlush(XtDisplay(w));
	
}





void ResPasteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	int ind=(int)client_data;
 
	XtFree(gr_res_tab[ind]->last_state);
	gr_res_tab[ind]->last_state=XmTextGetString(gr_res_tab[ind]->resotext);
	gr_res_tab[ind]->last_position=
	 	XmTextGetInsertionPosition(gr_res_tab[ind]->resotext);   
	XmTextPaste(gr_res_tab[ind]->resotext);
}





void ResSaveCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   char   *save_file, *reso_text, msg_str[1001];
   int    ind=(int)client_data;

   if (gr_res_tab[ind]->res_save_pathname == NULL)
      return;
   
   save_file = gr_res_tab[ind]->res_save_pathname;

   /* Copy resource window contents into save_file */
		
   reso_text = XmTextGetString(gr_res_tab[ind]->resotext);
   if (file_create(save_file, reso_text) == -1)
   {
	XtFree(reso_text);
	sprintf(msg_str,"Can't open file %s",save_file);
	OpenMsgBox(widgtab[ErrorBoxID], msg_str);
	return;
   }
   XtFree(reso_text);
   sprintf(msg_str,
         "the resources matching %s \nhave been saved as displayed into :\n%s",
         gr_res_tab[ind]->resfilter, save_file);
   OpenMsgBox(widgtab[InfoBoxID], msg_str);

}





void ServPrepareUpdateCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	server_to_update=(int)client_data;
	dev_dc_flag = GR_SERV;
}





void UndoCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   char             *txt_tmp;
   XmTextPosition   pos_tmp;
   int              index=(int) client_data;

   txt_tmp=XmTextGetString(widgtab[index]);
   pos_tmp=XmTextGetInsertionPosition(widgtab[index]);
   XmTextSetString(widgtab[index], last_state);
   XmTextSetInsertionPosition(widgtab[index], last_cursor_position);
   XtFree(last_state);
   last_state=txt_tmp;
   last_cursor_position=pos_tmp;
}





void ResCutCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	Time time;
 	int ind=(int)client_data;
 	XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;

	XtFree(gr_res_tab[ind]->last_state);
	gr_res_tab[ind]->last_state=XmTextGetString(gr_res_tab[ind]->resotext);
	gr_res_tab[ind]->last_position=
	 	XmTextGetInsertionPosition(gr_res_tab[ind]->resotext);   
	time=acs->event->xbutton.time;
	XmTextCut(gr_res_tab[ind]->resotext, time);
}





void CutCb( Widget w, XtPointer client_data, XtPointer call_data)
{
        Time time;
	int  index=(int) client_data;


        XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*) call_data;
	XtFree(last_state);
	last_state=XmTextGetString(widgtab[index]);
	last_cursor_position=
	 	XmTextGetInsertionPosition(widgtab[index]);   
	time=acs->event->xbutton.time;
	XmTextCut(widgtab[index],time);
}





void CopyCb( Widget w, XtPointer client_data, XtPointer call_data)
{
        Time time;
	int  index=(int) client_data;

        XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*) call_data;
	time=acs->event->xbutton.time;
	XmTextCopy(widgtab[index],time);
}





void DeleteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	int  index=(int) client_data;

	XtFree(last_state);
	last_state=XmTextGetString(widgtab[index]);
	last_cursor_position=
	 	XmTextGetInsertionPosition(widgtab[index]);
	XmTextRemove(widgtab[index]);
}





void DevCutCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	Time time;
 	int ind=(int)client_data;
 	XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;

	XtFree(dev_tab[ind]->last_state);
	dev_tab[ind]->last_state=XmTextGetString(dev_tab[ind]->resotext);
	dev_tab[ind]->last_position=
	 	XmTextGetInsertionPosition(dev_tab[ind]->resotext);   
	time=acs->event->xbutton.time;
	XmTextCut(dev_tab[ind]->resotext,time);
}


void DevDcCutCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	Time time;
 	int ind=(int)client_data;
 	XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;

	XtFree(dev_dc_tab[ind]->last_state);
	dev_dc_tab[ind]->last_state=XmTextGetString(dev_dc_tab[ind]->resotext);
	dev_dc_tab[ind]->last_position = XmTextGetInsertionPosition(dev_dc_tab[ind]->resotext);   
	time = acs->event->xbutton.time;
	XmTextCut(dev_dc_tab[ind]->resotext,time);
}




void PreparePrintCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 FILE *stream; 
 char *txt, file[48];   
	
	sprintf(file, "/tmp/greta%d.txt", pid);

	/* Fill greta.txt */
	stream=fopen(file,"w");

	txt=XmTextGetString(widgtab[MainTextID]);
	fputs(txt,stream);
	XtFree(txt);
	xsSetTitle(widgtab[PrintFormID], "Print Main Window");

	/* Terminate */
	fclose(stream);
	
}





void PrepareServDelCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    char s[256];
    int ind=(int)client_data;
    
/* Position the sdd.c variable server_to_delete */
    server_to_delete=ind;
    
/* Set the Server Delete Dialog title */
    sprintf(s,"Delete %s",serv_tab[ind]->servname);
    xsSetTitle(widgtab[ServDelOpFormID], s);

}





void ccb_make_parent_def_button( Widget w, XtPointer client_data, XtPointer call_data)
{

   XtVaSetValues( XtParent(w), XmNdefaultButton, w, NULL);
}






void DismissCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	int   index=(int) client_data;

	dev_dc_flag = GR_DEV;
	XtUnmanageChild(widgtab[index]);
}




void DevClickCb( Widget w, XtPointer client_data, XtPointer call_data)
{
  char          *d, *f, *m, *s;
  XmString      xmstr = NULL;
  int           index=(int) client_data;

	s=(char *)malloc(3*20+strlen("//"));
	switch(index)
	{
	case DomainListID :
		XmListDeselectAllItems(widgtab[FamilyListID]);
		XmListDeselectAllItems(widgtab[MemberListID]);
		d=xsListGetBrowseSelection(widgtab[DomainListID]);
		strcpy(s,d);
		strcat(s,"/");
	        xsTextFieldSetString(widgtab[DevSelectionTFID],s);
	        strcat(s,"*");
	        xsTextFieldSetString(widgtab[DevFilterTFID],s);
		break;
		
	case FamilyListID :
		XmListDeselectAllItems(widgtab[MemberListID]);
		d=xsListGetBrowseSelection(widgtab[DomainListID]);
		f=xsListGetBrowseSelection(widgtab[FamilyListID]);
		if (!strcmp(d,dev_filter.dom))
			/* then change the domlist sel to match the memorized dom
			   ie the dom corresponding to the family just clicked */
			xmstr=XmStringCreateLocalized(dev_filter.dom);
		XmListSelectItem(widgtab[DomainListID],xmstr , 0);
		strcpy(s,dev_filter.dom);
		strcat(s,"/");
		strcat(s,f);
		strcat(s,"/");
	        xsTextFieldSetString(widgtab[DevFilterTFID],s);
	        strcat(s,"*");
	        xsTextFieldSetString(widgtab[DevSelectionTFID],s);
		XtFree(f);
		if (xmstr != NULL)
			XmStringFree(xmstr);
		break;
		
	case MemberListID :
		d=xsListGetBrowseSelection(widgtab[DomainListID]);
		f=xsListGetBrowseSelection(widgtab[FamilyListID]);
		m=xsListGetBrowseSelection(widgtab[MemberListID]);
		if (strcmp(d,dev_filter.dom))
		{
			/* then change the domlist sel to match the memorized dom
			   ie the dom corresponding to the family just clicked */
			xmstr=XmStringCreateLocalized(dev_filter.dom);
			XmListSelectItem(widgtab[DomainListID], xmstr,1);
			XmStringFree(xmstr);
		}
		if (strcmp(f,dev_filter.fam))
		{
			/* then change the famlist sel to match the memorized fam
			   ie the fam corresponding to the member just clicked */
			xmstr=XmStringCreateLocalized(dev_filter.fam);
			XmListSelectItem(widgtab[FamilyListID], xmstr,0);
		}
		strcpy(s,dev_filter.dom);
		strcat(s,"/");
		strcat(s,dev_filter.fam);
		strcat(s,"/");
		xsTextFieldSetString(widgtab[DevFilterTFID],s);
	        strcat(s,m);
	        xsTextFieldSetString(widgtab[DevSelectionTFID],s);
		XtFree(f);
		XtFree(m);
		if (xmstr != NULL)
			XmStringFree(xmstr);
		break;
	}
	XtFree(d);
	free(s);
}





void DevFilterCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *s;
 	char *dom, *fam, *strerr;
 	char **str_tbl;
 	long num;
 	XmString xmstr;
 	XmString *xmstr_tbl;
 	Arg args[512];	     
 	Cardinal argcnt=0;
 	int pos;
	DevLong error;
	long i;

    	xsSetCursor(widgtab[DevSelFormID], XC_watch);
    	XFlush(XtDisplay(w)); 
   
/* syntaxic verification : ending the filter is not necessary */

 	s=XmTextFieldGetString(widgtab[DevFilterTFID]);
 	dom=strtok(s,"/");
 	fam=strtok((char *)0,"/");

/* Handle the dom field */

	xmstr=XmStringCreateLocalized(dom);
	pos=XmListItemPos(widgtab[DomainListID],xmstr);
	XmStringFree(xmstr);
	if (!pos) 
	{
		OpenMsgBox(widgtab[ErrorBoxID],"Invalid Domain");
		XtFree(s);
		xsUnsetCursor(widgtab[DevSelFormID]);
    		XFlush(XtDisplay(w));    
		return; 
	}
	
/* Dom belongs to domainslist */
/* Update the dom filter memorized and the familiylist */

	if (strcmp(dev_filter.dom,dom))
	{
		strcpy(dev_filter.dom,dom);
		XmListDeleteAllItems(widgtab[FamilyListID]);
		if (db_getdevfamilylist(dom,&num,&str_tbl,&error))
		{
			XtFree(s);
			strerr = dev_error_str(error);
			OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
			xsUnsetCursor(widgtab[DevSelFormID]);
    			XFlush(XtDisplay(w));    
			return;
		}
		xmstr_tbl = etxsXmStringTableCreate(str_tbl,num);
		for (i = 0;i < num;i++)
			free(str_tbl[i]);
		free(str_tbl);
		XmListAddItems(widgtab[FamilyListID], xmstr_tbl, num, 0);
		etxsXmStringTableFree(xmstr_tbl, num);
	}
	
/* Handle the fam field */
/* Is there a fam field ? */

	if (!strcmp(fam,"*") || (fam == NULL))
	{
	
/* Terminate the treatment */

		XtFree(s);
		strcpy(dev_filter.fam,"");
		XmListDeleteAllItems(widgtab[MemberListID]);
		
/* Select the first family of the list and meanwhile simulate
   a click that position the text fields */
   
		XmListSelectPos(widgtab[FamilyListID],1,TRUE);
		xsUnsetCursor(widgtab[DevSelFormID]);
    		XFlush(XtDisplay(w));    
		return; 
	}
	
/* Is the fam field valid ? */

	xmstr=XmStringCreateLocalized(fam);
	pos=XmListItemPos(widgtab[FamilyListID],xmstr);
	XmStringFree(xmstr);

	if (!pos) 
	{
		OpenMsgBox(widgtab[ErrorBoxID],"Invalid Family");
		XtFree(s);
		xsUnsetCursor(widgtab[DevSelFormID]);
    		XFlush(XtDisplay(w));    
		return; 
	}
	
/* fam belongs to Familieslist */
/* Update the fam filter memorized and the memberslist */

	strcpy(dev_filter.fam,fam);
	XmListDeleteAllItems(widgtab[MemberListID]);
	if (db_getdevmemberlist(dom,fam,&num,&str_tbl,&error))
	{
		strerr = dev_error_str(error);
		XtFree(s);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		xsUnsetCursor(widgtab[DevSelFormID]);
    		XFlush(XtDisplay(w));    
		return;
	}
	xmstr_tbl = etxsXmStringTableCreate(str_tbl,num);
	for (i = 0;i < num;i++)
		free(str_tbl[i]);
	free(str_tbl);
	XmListAddItems(widgtab[MemberListID], xmstr_tbl, num, 0);
	etxsXmStringTableFree(xmstr_tbl, num);
	
/* Terminate */

	XtFree(s);
	
/* Select the first member of the list and meanwhile simulate
   a click that position the text fields */
   
	XmListSelectPos(widgtab[MemberListID],1,TRUE);
	xsUnsetCursor(widgtab[DevSelFormID]);
	XFlush(XtDisplay(w));
}





void DevDismissCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char s[256];
 	int ind=(int)client_data;

	XtUnmanageChild(dev_tab[ind]->window);
	XtDestroyWidget(dev_tab[ind]->window);
	dev_remove(ind);
}


void DevDcDismissCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char s[256];
 	int ind=(int)client_data;

	XtUnmanageChild(dev_dc_tab[ind]->window);
	XtDestroyWidget(dev_dc_tab[ind]->window);
	dev_dc_remove(ind);
}


void DevUndoCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   	char *txt_tmp;
   	XmTextPosition pos_tmp;
 
   	int ind=(int)client_data;
 
   	txt_tmp=XmTextGetString(dev_tab[ind]->resotext);
   	pos_tmp=XmTextGetInsertionPosition(dev_tab[ind]->resotext);
   	XmTextSetString(dev_tab[ind]->resotext, dev_tab[ind]->last_state);
   	XmTextSetInsertionPosition(dev_tab[ind]->resotext,
   	dev_tab[ind]->last_position);
   	XtFree(dev_tab[ind]->last_state);
   	dev_tab[ind]->last_state=txt_tmp;
   	dev_tab[ind]->last_position=pos_tmp;
}



void DevDcUndoCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   	char *txt_tmp;
   	XmTextPosition pos_tmp;
 
   	int ind=(int)client_data;
 
   	txt_tmp=XmTextGetString(dev_dc_tab[ind]->resotext);
   	pos_tmp=XmTextGetInsertionPosition(dev_dc_tab[ind]->resotext);
   	XmTextSetString(dev_dc_tab[ind]->resotext, dev_dc_tab[ind]->last_state);
   	XmTextSetInsertionPosition(dev_dc_tab[ind]->resotext,dev_dc_tab[ind]->last_position);
   	XtFree(dev_dc_tab[ind]->last_state);
   	dev_dc_tab[ind]->last_state=txt_tmp;
   	dev_dc_tab[ind]->last_position=pos_tmp;
}




void DevCopyCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	Time time;
 	int ind=(int)client_data;
 	XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;
 
	time=acs->event->xbutton.time;
	XmTextCopy(dev_tab[ind]->resotext,time);
}



void DevDcCopyCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	Time time;
 	int ind=(int)client_data;
 	XmAnyCallbackStruct *acs = (XmAnyCallbackStruct*)call_data;
 
	time = acs->event->xbutton.time;
	XmTextCopy(dev_dc_tab[ind]->resotext,time);
}


void DevDcPingCb(Widget w, XtPointer client_data, XtPointer call_data)
{
	int ind = (int)client_data;
	char dev_name[DEV_NAME_LENGTH];
	
	strcpy(dev_name,dev_dc_tab[ind]->devname);
	
	devping(dev_name,w,dev_dc_tab[ind]->window);
}


void DevPingCb(Widget w, XtPointer client_data, XtPointer call_data)
{
	int ind = (int)client_data;
	char dev_name[DEV_NAME_LENGTH];
	
	strcpy(dev_name,dev_tab[ind]->devname);
	
	devping(dev_name,w,dev_tab[ind]->window);
}



void devping(char *dev_name, Widget w, Widget fo)
{
	devserver ds;
	DevLong error;
	char *strerr;
	char mess[160];
	
    	xsSetCursor(fo, XC_watch);
    	XFlush(XtDisplay(w));

/* Import the device */

	if (dev_import(dev_name,READ_ACCESS,&ds,&error))
	{
		strcpy(mess,"Device import failed !!!!\n");
		strerr = dev_error_str(error);
		strcat(mess,strerr);
		OpenMsgBox(widgtab[ErrorBoxID], mess);
		free(strerr);
		xsUnsetCursor(fo);
	    	XFlush(XtDisplay(w));
		return;
	}

/* Ping the device */

	if (dev_ping(ds,&error))
	{
		strcpy(mess,"Device ping failed !!!!\n");
		if (error == DevErr_CommandNotImplemented)
		{
			strcat(mess,"Device server too old. It does not support ping command. Relink it with new DSAPI library !!");
		}
		else
		{
			strerr = dev_error_str(error);
			strcat(mess,strerr);
		}
		OpenMsgBox(widgtab[ErrorBoxID], mess);
		if (error != DevErr_CommandNotImplemented)
			free(strerr);
		dev_free(ds,&error);
		xsUnsetCursor(fo);
	    	XFlush(XtDisplay(w));
		return;
	}

	sprintf(mess,"Device %s answers correctly to ping request",dev_name);	
	OpenMsgBox(widgtab[InfoBoxID],mess);

/* Free the device */

	dev_free(ds,&error);
		
	xsUnsetCursor(fo);
	XFlush(XtDisplay(w));
	return;
}


void DevSelOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	if ((booloptab[devdisplay_dc] == True) || (booloptab[devdisplay_hdb] == True))
		DevDcSelOK(w,client_data,call_data);
	else
		DevSelOK(w,client_data,call_data);
}


void DevSelOK( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *reso_str, *dev_name, *strerr, s[256];
 	char file[48];
 	Widget topLevelShell, mainWindow;
 	int resu, index;
	db_devinfo_call info;
	DevLong error;
	char tmp[100];
	char info_str[500];
	long i,num;
	char **res_array;

    	xsSetCursor(widgtab[DevSelFormID], XC_watch);
    	XFlush(XtDisplay(w));
        
/* Verify that there is a device structure index available */

	if ((index=new_dev_index()) < 0)
	{
		OpenMsgBox(widgtab[ErrorBoxID]," No more device window available ");
		xsUnsetCursor(widgtab[DevSelFormID]);
	    	XFlush(XtDisplay(w));
		return ;
	}

/* Fetch the Device Selection Text Field content and fill dev_name with it */

 	dev_name = XmTextFieldGetString(widgtab[DevSelectionTFID]);

/* Get device information */

    	if(db_deviceinfo(dev_name,&info,&error))
    	{
		strerr = dev_error_str(error);
		XtFree(dev_name);
		free_dev_index(index);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		xsUnsetCursor(widgtab[DevSelFormID]);
	    	XFlush(XtDisplay(w));
		return;
	}
	
/* Get device resource */

	if (db_deviceres(1,&dev_name,&num,&res_array,&error))
	{
		if (error == DbErr_DomainDefinition)
		{
			num = 0;
		}
		else
		{
			strerr = dev_error_str(error);
			XtFree(dev_name);
			free_dev_index(index);
			OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
	}
	
/* Position topLevelShell and mainWindow to pass them to 
   xsDeviceWindowCreateManaged*/

	mainWindow=XtParent(XtParent(widgtab[DevSelFormID])); 
	topLevelShell=XtParent(mainWindow);
	  
/* Create the window */

	xsDeviceWindowCreate(topLevelShell, mainWindow, index, dev_name);

/* Create string in motif style from db server call result */

	devinfo_str(&info,dev_name,info_str);
	
/* Create Motif dtyle string */

	if (num != 0)
	{	
		if (xsCreateStringForText(res_array,num,&reso_str))
		{
			XtFree(dev_name);
			free_dev_index(index);
			OpenMsgBox(widgtab[ErrorBoxID], "Can't allocate memory");
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
	}
	else
	{
		if ((reso_str = malloc(2)) == NULL)
		{
			XtFree(dev_name);
			free_dev_index(index);
			OpenMsgBox(widgtab[ErrorBoxID], "Can't allocate memory");
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
		strcpy(reso_str,"");
	}
	
/* Copy some interesting device info into device structure */

	dev_tab[index]->pid = info.pid;
	dev_tab[index]->pn = info.program_num;
	strcpy(dev_tab[index]->host_name,info.host_name);
	strcpy(dev_tab[index]->proc_name,info.process_name);
	strcpy(dev_tab[index]->pers_name,info.personal_name);
	dev_tab[index]->exported = info.device_exported;
	
/* Fill the text widgets */

	XmTextSetString(dev_tab[index]->infotext,info_str);
	XmTextSetString(dev_tab[index]->resotext,reso_str);
	
/* Initialize last_state and last_position for Undo */

	dev_tab[index]->last_state = strdup(reso_str);
	dev_tab[index]->last_position = 0; 
	dev_tab[index]->dev_save_pathname = NULL; 
	
/* Upkeep of a reference resource file for Update, set the file name field  */

	sprintf(file, "/tmp/greta%d_dev%d.res", pid, index);
	strcpy(dev_tab[index]->file, file);
	dev_tab[index]->res_nb = num;
	devresfile_create(file, reso_str);

/* Manage the device window */

	XtManageChild(dev_tab[index]->window);
	
	if (num == 0)
	{
    		sprintf(s,"The device %s has no resources yet\n",dev_name);
    		OpenMsgBox(widgtab[InfoBoxID], s);
	}
	xsUnsetCursor(widgtab[DevSelFormID]);
	XFlush(XtDisplay(w));

/* Free memory */
	
	XtFree(dev_name);
	if (num != 0)
	{
		for (i = 0;i < num;i++)
			free(res_array[i]);
		free(res_array);
	}
	free(reso_str);
}


void DevDcSelOK( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *reso_str, *dev_name, *dchdb_str, *strerr, s[256];
 	char file[48];
 	Widget topLevelShell, mainWindow;
 	int resu, index;
	db_devinfo_call info;
	DevLong error;
	long l;
	char tmp[100];
	char info_str[500];
	char hdb_str[2000];
	char dc_str[800];
	long i,num;
	char **res_array;

    	xsSetCursor(widgtab[DevSelFormID], XC_watch);
    	XFlush(XtDisplay(w));
        
/* Verify that there is a device structure index available */

	if ((index=new_dev_dc_index()) < 0)
	{
		OpenMsgBox(widgtab[ErrorBoxID]," No more device window available ");
		xsUnsetCursor(widgtab[DevSelFormID]);
	    	XFlush(XtDisplay(w));
		return ;
	}

/* Fetch the Device Selection Text Field content and fill dev_name with it */

 	dev_name = XmTextFieldGetString(widgtab[DevSelectionTFID]);

/* Get device information */

    	if(db_deviceinfo(dev_name,&info,&error))
    	{
		strerr = dev_error_str(error);
		XtFree(dev_name);
		free_dev_dc_index(index);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
		xsUnsetCursor(widgtab[DevSelFormID]);
	    	XFlush(XtDisplay(w));
		return;
	}

/* Get device resource */

	if (db_deviceres(1,&dev_name,&num,&res_array,&error))
	{
		if (error == DbErr_DomainDefinition)
		{
			num = 0;
		}
		else
		{
			strerr = dev_error_str(error);
			XtFree(dev_name);
			free_dev_dc_index(index);
			OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
	}

/* If needed, get DC info */

	if (booloptab[devdisplay_dc] == True)
	{
		if (getdc_info(dev_name,dc_str))
		{
			strcpy(dc_str,"Can't get DC information !!\n");
		}
	}

/* If needed, get HDB info */

	if (booloptab[devdisplay_hdb] == True)
	{
		if (gethdb_info(dev_name,hdb_str))
		{
			strcpy(hdb_str,"Can't get HDB information !!\n");
		}
	}

/* Build only one string with result of DC and HDB info */

	if ((booloptab[devdisplay_dc] == True) && (booloptab[devdisplay_hdb] == True))
	{
		l = strlen(dc_str) + strlen(hdb_str) + 120;
		
		if ((dchdb_str = (char *)malloc(l)) == NULL)
		{
			XtFree(dev_name);
			free_dev_dc_index(index);
			OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
		strcpy(dchdb_str,"          DC informations\n\n");
		strcat(dchdb_str,dc_str);
		strcat(dchdb_str,"\n          HDB informations\n\n");
		strcat(dchdb_str,hdb_str);
	}
	else if (booloptab[devdisplay_dc] == True)
	{
		l = strlen(dc_str) + 60;
		
		if ((dchdb_str = (char *)malloc(l)) == NULL)
		{
			XtFree(dev_name);
			free_dev_dc_index(index);
			OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
		strcpy(dchdb_str,"          DC informations\n\n");
		strcat(dchdb_str,dc_str);
	}
	else
	{
		l = strlen(hdb_str) + 60;
		
		if ((dchdb_str = (char *)malloc(l)) == NULL)
		{
			XtFree(dev_name);
			free_dev_dc_index(index);
			OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
		strcpy(dchdb_str,"          HDB informations\n\n");
		strcat(dchdb_str,hdb_str);
	}
					
/* Position topLevelShell and mainWindow to pass them to 
   xsDeviceWindowCreateManaged*/

	mainWindow=XtParent(XtParent(widgtab[DevSelFormID])); 
	topLevelShell=XtParent(mainWindow);
	  
/* Create the window */

	xsDevDcHdbWindowCreate(topLevelShell, mainWindow, index, dev_name);

/* Create string in motif style from db server call result */

	devinfo_str(&info,dev_name,info_str);
	
/* Create string in Motif style */

	if (num != 0)
	{	
		if (xsCreateStringForText(res_array,num,&reso_str))
		{
			XtFree(dev_name);
			free_dev_dc_index(index);
			free(dchdb_str);
			OpenMsgBox(widgtab[ErrorBoxID], "Can't allocate memory");
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
	}
	else
	{
		if ((reso_str = malloc(2)) == NULL)
		{
			XtFree(dev_name);
			free_dev_dc_index(index);
			free(dchdb_str);
			OpenMsgBox(widgtab[ErrorBoxID], "Can't allocate memory");
			xsUnsetCursor(widgtab[DevSelFormID]);
	    		XFlush(XtDisplay(w));
			return;
		}
		strcpy(reso_str,"");
	}
	
/* Copy some interesting device info into device structure */

	dev_dc_tab[index]->pid = info.pid;
	dev_dc_tab[index]->pn = info.program_num;
	strcpy(dev_dc_tab[index]->host_name,info.host_name);
	strcpy(dev_dc_tab[index]->proc_name,info.process_name);
	strcpy(dev_dc_tab[index]->pers_name,info.personal_name);
	dev_dc_tab[index]->exported = info.device_exported;
	
/* Fill the text widgets */

	XmTextSetString(dev_dc_tab[index]->infotext,info_str);
	XmTextSetString(dev_dc_tab[index]->resotext,reso_str);
	XmTextSetString(dev_dc_tab[index]->dctext,dchdb_str);
		
/* Initialize last_state and last_position for Undo */

	dev_dc_tab[index]->last_state = strdup(reso_str);
	dev_dc_tab[index]->last_position = 0; 
	dev_dc_tab[index]->dev_save_pathname = NULL; 
	
/* Upkeep of a reference resource file for Update, set the file name field  */

	sprintf(file, "/tmp/greta%d_devdc%d.res", pid, index);
	strcpy(dev_dc_tab[index]->file, file);
	dev_dc_tab[index]->res_nb = num;
	devresfile_create(file, reso_str);

/* Manage the device window */

	XtManageChild(dev_dc_tab[index]->window);
	
	if (num == 0)
	{
    		sprintf(s,"The device %s has no resources yet\n",dev_name);
    		OpenMsgBox(widgtab[InfoBoxID], s);
	}
	xsUnsetCursor(widgtab[DevSelFormID]);
	XFlush(XtDisplay(w));

/* Free memory */
	
	XtFree(dev_name);
	if (num != 0)
	{
		for (i = 0;i < num;i++)
			free(res_array[i]);
		free(res_array);
		free(reso_str);
	}
	free(dchdb_str);
}


void DevDelOKCb(Widget w, XtPointer client_data, XtPointer call_data)
{
	DevLong error;
	db_error db_err;
	char *strerr;
	char *local_dev_name;
	Widget w_curs;
	
	if (dev_dc_flag == GR_DEV_DC)
		w_curs = dev_dc_tab[device_to_delete]->window;
	else
		w_curs = dev_tab[device_to_delete]->window;

    	xsSetCursor(XtParent(w_curs), XC_watch);
    	XFlush(XtDisplay(w));

	if (dev_dc_flag == GR_DEV_DC)
		local_dev_name = dev_dc_tab[device_to_delete]->devname;
	else
		local_dev_name = dev_tab[device_to_delete]->devname;
	dev_dc_flag = GR_DEV;
		
/* Delete device fist */
		
	if (db_devicedelete(local_dev_name,&error))
	{
		strerr = dev_error_str(error);
    		OpenMsgBox(widgtab[InfoBoxID], strerr);
		free(strerr);
    		xsUnsetCursor(XtParent(w_curs));
    		XFlush(XtDisplay(w));
		return; 
	}

/* Also delete resources if needed */

    	if (XmToggleButtonGetState(widgtab[DevDelWResTBID]))
	{
		if (db_devicedeleteres(1,&local_dev_name,&db_err))
		{
			if (db_err.error_code != DbErr_DomainDefinition)
			{
				strerr = dev_error_str(db_err.error_code);
				OpenMsgBox(widgtab[InfoBoxID], strerr);
				free(strerr);
    				xsUnsetCursor(XtParent(w_curs));
    				XFlush(XtDisplay(w));
				return;
			} 
		}
	}
		
    	xsUnsetCursor(XtParent(w_curs));
    	XFlush(XtDisplay(w));    
}



void DevPasteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   	int    ind=(int)client_data;
 
   	XtFree(dev_tab[ind]->last_state);
   	dev_tab[ind]->last_state = XmTextGetString(dev_tab[ind]->resotext);
   	dev_tab[ind]->last_position=
        XmTextGetInsertionPosition(dev_tab[ind]->resotext);   
   	XmTextPaste(dev_tab[ind]->resotext);
}



void DevDcPasteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   	int    ind=(int)client_data;
 
   	XtFree(dev_dc_tab[ind]->last_state);
   	dev_dc_tab[ind]->last_state = XmTextGetString(dev_dc_tab[ind]->resotext);
   	dev_dc_tab[ind]->last_position = XmTextGetInsertionPosition(dev_dc_tab[ind]->resotext);   
   	XmTextPaste(dev_dc_tab[ind]->resotext);
}




void DevSaveCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   char   *save_file, *reso_text, msg_str[1001];
   int    ind=(int)client_data;

   if (dev_tab[ind]->dev_save_pathname == NULL)
      return;
   
   save_file = dev_tab[ind]->dev_save_pathname;

   /* Copy resource window contents into save_file */
		
   reso_text = XmTextGetString(dev_tab[ind]->resotext);
   if (devresfile_create(save_file, reso_text) == -1)
   {
	XtFree(reso_text);
	sprintf(msg_str,"Can't open file %s",save_file);
	OpenMsgBox(widgtab[ErrorBoxID], msg_str);
	return;
   }
   XtFree(reso_text);
   sprintf(msg_str,
           "the resources text of %s \nhas been saved as displayed into :\n%s",
           dev_tab[ind]->devname, save_file);
   OpenMsgBox(widgtab[InfoBoxID], msg_str);
}




void DevDcSaveCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   char   *save_file, *reso_text, msg_str[1001];
   int    ind=(int)client_data;

   if (dev_dc_tab[ind]->dev_save_pathname == NULL)
      return;
   
   save_file = dev_dc_tab[ind]->dev_save_pathname;

   /* Copy resource window contents into save_file */
		
   reso_text = XmTextGetString(dev_dc_tab[ind]->resotext);
   if (devresfile_create(save_file, reso_text) == -1)
   {
	XtFree(reso_text);
	sprintf(msg_str,"Can't open file %s",save_file);
	OpenMsgBox(widgtab[ErrorBoxID], msg_str);
	return;
   }
   XtFree(reso_text);
   sprintf(msg_str,
           "the resources text of %s \nhas been saved as displayed into :\n%s",
           dev_dc_tab[ind]->devname, save_file);
   OpenMsgBox(widgtab[InfoBoxID], msg_str);
}




void CreationCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	int   index=(int) client_data;

	widgtab[index]=w;
	
	switch(index)
	{
	case InfoBoxID :
		xsTransformToInfoBox(w);
	   	break;
	case ErrorBoxID :
		xsTransformToInfoBox(w);
	    	break;
	case QuitMsgBoxID :
		xsTransformToQuestionBox(w);
	    	break;
	case ServUnregBoxID :
		xsTransformToQuestionBox(w);
	    	break;
	case ServUpdateBoxID :
		xsTransformToQuestionBox(w);
	    	break;
	case DevUpdateBoxID :
		xsTransformToQuestionBox(w);
	    	break;
	case ResUpdateBoxID :
		xsTransformToQuestionBox(w);
	    	break;
	case ServRestartBoxID :
		xsTransformToQuestionBox(w);
	}
}





void ResPrepareUpdateCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    	respool_to_update = (int)client_data;
	dev_dc_flag = GR_RES;
}





void DevPrepareUpdateCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    device_to_update=(int)client_data;
    dev_dc_flag = GR_DEV;
}

void DevDcPrepareUpdateCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    device_to_update=(int)client_data;
    dev_dc_flag = GR_DEV_DC;
}

void DevPreparePrintCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	int ind=(int)client_data;
 	FILE *stream; 
 	char txt[256], file[48];    
 	char *framed_title,*info,*res; 
	
	sprintf(file, "/tmp/greta%d.txt", pid);

/* Fill greta.txt */

	stream=fopen(file, "w");

/* Put the displayed device name as a title */

    	sprintf(txt,"Device %s",dev_tab[ind]->devname);
	framed_title=(char *)frame(txt);
	fputs(framed_title,stream);
	free(framed_title);
	
/* Get the infoText and resourceText contents */

	info=XmTextGetString(dev_tab[ind]->infotext);
	res=XmTextGetString(dev_tab[ind]->resotext);
			
/* Put the info text widget content */

	sprintf(txt,"\n\nInformations :\n------------\n\n");
	fputs(txt,stream);
	fputs(info,stream);
	XtFree(info);
			
/* Put the resources text widget content */

	sprintf(txt,"\n\nResources :\n---------\n\n");
	fputs(txt,stream);
	fputs(res,stream);
	XtFree(res);

/* Terminate */

	fclose(stream);
	sprintf(txt,"Print device %s",dev_tab[ind]->devname);
	xsSetTitle(widgtab[PrintFormID], txt);
	
}


void DevDcPreparePrintCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	int ind=(int)client_data;
 	FILE *stream; 
 	char txt[256], file[48];    
 	char *framed_title,*info,*res,*dc; 
	
	sprintf(file, "/tmp/greta%d.txt", pid);

/* Fill greta.txt */

	stream=fopen(file, "w");

/* Put the displayed device name as a title */

    	sprintf(txt,"Device %s",dev_dc_tab[ind]->devname);
	framed_title=(char *)frame(txt);
	fputs(framed_title,stream);
	free(framed_title);
	
/* Get the infoText and resourceText contents */

	info = XmTextGetString(dev_dc_tab[ind]->infotext);
	res = XmTextGetString(dev_dc_tab[ind]->resotext);
	dc = XmTextGetString(dev_dc_tab[ind]->dctext);
			
/* Put the info text widget content */

	sprintf(txt,"\n\nDB Informations :\n---------------\n\n");
	fputs(txt,stream);
	fputs(info,stream);
	XtFree(info);
	
/* Put the dc text widget content */

	sprintf(txt,"\n\nDC/HDB Informations :\n-------------------\n\n");
	fputs(txt,stream);
	fputs(dc,stream);
	XtFree(dc);
				
/* Put the resources text widget content */

	sprintf(txt,"\n\nResources :\n---------\n\n");
	fputs(txt,stream);
	fputs(res,stream);
	XtFree(res);

/* Terminate */

	fclose(stream);
	sprintf(txt,"Print device %s",dev_dc_tab[ind]->devname);
	xsSetTitle(widgtab[PrintFormID], txt);
	
}


void ResPreparePrintCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	int ind=(int)client_data;
 	FILE *stream; 
 	char txt[256], file[48];    
 	char *framed_title, *res; 
	
	sprintf(file, "/tmp/greta%d.txt", pid);

/* Fill greta.txt */
	
	stream=fopen(file, "w");

/* Put the displayed filter as a title */

    	sprintf(txt,"Resources pool %s",gr_res_tab[ind]->resfilter);
	framed_title=(char *)frame(txt);
	fputs(framed_title, stream);
	free(framed_title);
	fputs("\n\n", stream);
	
/* Put the resources text widget content */

	res=XmTextGetString(gr_res_tab[ind]->resotext);
	fputs(res, stream);
	XtFree(res);

/* Terminate */

	fclose(stream);
	sprintf(txt, "Print resources matching %s",gr_res_tab[ind]->resfilter);
	xsSetTitle(widgtab[PrintFormID], txt);
	
}





void ServPasteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 Display *display;
 Widget dest;
 int ind=(int)client_data;

/* Set dest to which editable text has to be undo . (devstext or resotext) */
	display=XtDisplay(serv_tab[ind]->window);
	dest=XmGetDestination(display);

/* Verify dest==resotext or devstext */	
	if ((dest!=serv_tab[ind]->devstext)&&(dest!=serv_tab[ind]->resotext))
		return;

/* Save and paste */
	save_text(ind);
	XmTextPaste(dest);
}





void ResDeleteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	int ind=(int)client_data;

	free(gr_res_tab[ind]->last_state);
	gr_res_tab[ind]->last_state=XmTextGetString(gr_res_tab[ind]->resotext);
	gr_res_tab[ind]->last_position=
	 	XmTextGetInsertionPosition(gr_res_tab[ind]->resotext);   
	XmTextRemove(gr_res_tab[ind]->resotext);
}





void ServFilterCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *s, *class, *strerr, sel[256];
 	char      msg_err[501];
 	char **str_tbl;
 	long num,i;
	DevLong error;
 	XmString xmstr;
 	XmString *xmstr_tbl;
 	int l, pos;

    	xsSetCursor(widgtab[ServSelFormID], XC_watch);    
    	XFlush(XtDisplay(w));    
 	s=XmTextFieldGetString(widgtab[ServFilterTFID]);
 	
/* Syntaxical check : the filter must have exactly one occurrence of the
   '/' and the '*' character, and it must end it */
	
 	l=strlen(s);
 	if ((&(s[l-2])!=strchr(s,'/')) ||
 	    (&(s[l-1])!=strchr(s,'*')))
 	{
            	strcpy(msg_err, "        Syntaxical Error !\n");
            	strcat(msg_err, "The filter must be of the form :\n");
            	strcat(msg_err, "     \"class_name/");
            	strcat(msg_err, "*");
            	strcat(msg_err, "\"\n");
            	OpenMsgBox(widgtab[ErrorBoxID], msg_err);
            	XtFree(s);
            	xsUnsetCursor(widgtab[ServSelFormID]);
            	XFlush(XtDisplay(w));    
            	return ;
	}
	
/* syntaxical check is OK, go on */

	class=(char *)strtok(s,"/");
	
/* Semantical check */

	xmstr=XmStringCreateLocalized(class);
	pos=XmListItemPos(widgtab[ClassListID],xmstr);
	XmStringFree(xmstr);

	if (!pos) 
	{ 
		OpenMsgBox(widgtab[ErrorBoxID],"Invalid class name !");
		XtFree(s);
		xsUnsetCursor(widgtab[ServSelFormID]);
    		XFlush(XtDisplay(w));    
		return;
	}

/* semantical check is OK, go on */

	XmListSelectPos(widgtab[ClassListID],pos,TRUE);
	
	if (strcmp(class,serv_filter))
	{
		XmListDeleteAllItems(widgtab[PnameListID]);
		if (db_getdspersnamelist(class,&num,&str_tbl,&error))
		{
			strerr = dev_error_str(error);
			XtFree(s);
			OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
			xsUnsetCursor(widgtab[ServSelFormID]);
    			XFlush(XtDisplay(w));    
			return;
		}
		xmstr_tbl = etxsXmStringTableCreate(str_tbl,num);
		for (i = 0;i < num;i++)
			free(str_tbl[i]);
		free(str_tbl);
		XmListAddItems(widgtab[PnameListID],xmstr_tbl,num,0);		
		strcpy(serv_filter, class);
		etxsXmStringTableFree(xmstr_tbl,num);
	}
	
	XmListSelectPos(widgtab[PnameListID],1,TRUE);
	sprintf(sel, "%s/%s",class,xsListGetBrowseSelection(widgtab[PnameListID]));
	XtFree(s);
	xsTextFieldSetString(widgtab[ServSelectionTFID],sel);
	xsUnsetCursor(widgtab[ServSelFormID]);
   	XFlush(XtDisplay(w));    
}





void QuitCb( Widget w, XtPointer client_data, XtPointer call_data)
{
/* Configuration globals (initialized with SYS resources) */

	free(print_a2ps_options);
	free(print_lp_options);

/* Freeing of the application globals */

	free(version_lb);
	XtFree(last_state);
	
/* Globals from sdd.c, associated to the dynamic windows */

	free_dev_sdd();
	free_serv_sdd();
	free_res_sdd();
	
/* Exit program */

	exit(0);
	
}





void PrintCb( Widget w, XtPointer client_data, XtPointer call_data)
{

 char *a2op, *lpop, *tmp, *cmd, file[48]; 
 /* on recupere les TextFields et 
    on construit la cmd d'impression de greta.txt */
 int i, nb_copies;
 int length;/*calcul de la longueur de cmd pour allocation memoire*/

	sprintf(file, "/tmp/greta%d.txt", pid);

	/* Construction de la commande d'impression de greta.txt */
	a2op=XmTextFieldGetString(widgtab[A2psOptionsTextFID]);
	lpop=XmTextFieldGetString(widgtab[LpOptionsTextFID]);
	length=strlen("a2ps  |lp ")+strlen(file)+strlen(a2op)+strlen(lpop)+1; 
	cmd=(char *)malloc(length);
	sprintf(cmd, "a2ps %s %s|lp %s", a2op, file, lpop); 
	XtFree(a2op);
	XtFree(lpop);
	
	/* On lance l'impression nb_copies fois */
	tmp=XmTextFieldGetString(widgtab[CopiesNbTextFID]);
	sscanf(tmp,"%d",&nb_copies);
	XtFree(tmp);
	for(i=0;i<nb_copies;i++)
		system(cmd);
		
	/* liberation de cmd et fermeture du dialogue */ 
	free(cmd);
	remove(file);
	XtUnmanageChild(widgtab[PrintFormID]);
}





void PasteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	int    index=(int) client_data;


	XtFree(last_state);
	last_state=XmTextGetString(widgtab[index]);
	last_cursor_position= XmTextGetInsertionPosition(widgtab[index]);
	XmTextPaste(widgtab[index]);
}





void ServUnregOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	unsigned int diff;
	char *tmp;
	char ds_name[DS_NAME_LENGTH];
	char pers_name[DSPERS_NAME_LENGTH];
	DevLong error;
	char *strerr;
	
/* Split full server name */

	tmp = strchr(serv_tab[server_to_unreg]->servname,'/');
	diff = (unsigned int)(tmp++ - serv_tab[server_to_unreg]->servname);
	strncpy(ds_name,serv_tab[server_to_unreg]->servname,diff);
	ds_name[diff] = '\0';
	
	strcpy(pers_name,tmp);
	
/* Unregister server */
    
    	xsSetCursor(XtParent(w), XC_watch);    
    	XFlush(XtDisplay(w)); 
	   
	if (db_servunreg(ds_name,pers_name,&error))
	{
		strerr = dev_error_str(error);
		OpenMsgBox(widgtab[ErrorBoxID], strerr);
		free(strerr);
	}	
	xsUnsetCursor(XtParent(w));
    	XFlush(XtDisplay(w));    
	
}


void DialogCb( Widget w, XtPointer client_data, XtPointer call_data)
{  
	long num,i;
	DevLong error;
 	char **str_tbl;
 	XmString *xmstr_tbl;
 	char *strerr;
 	int index=(int) client_data;
	unsigned long pid;
	char host[40];
	char proc[40];
	char pers[40];
	char messerr[512];
	char dev[40];
	unsigned long diff;
	char *tmp;
	char tmp_dev[40];
	long exported;

/* switch on the widgets that has to be reinitialized each time they are 
   opened */
      
	switch(index)
	{
	case DevSelFormID :
	        xsSetCursor(XtParent(XtParent(XtParent(w))), XC_watch);
	        xsSetCursor(widgtab[MainTextID], XC_watch);
	        XFlush(XtDisplay(w));

/* Fill the domains list */

		XmListDeleteAllItems(widgtab[DomainListID]);
		if (db_getdevdomainlist(&num,&str_tbl,&error))
		{
			strerr = dev_error_str(error);
			OpenMsgBox(widgtab[ErrorBoxID],strerr);
			free(strerr);
	        	xsUnsetCursor(XtParent(XtParent(XtParent(w))));
	        	xsUnsetCursor(widgtab[MainTextID]);
	        	XFlush(XtDisplay(w));
			return;
		}
		xmstr_tbl=etxsXmStringTableCreate(str_tbl,num);
		for (i = 0;i < num;i++)
			free(str_tbl[i]);
		free(str_tbl);
		XmListAddItems(widgtab[DomainListID],xmstr_tbl,num,0);
		etxsXmStringTableFree(xmstr_tbl, num);
		
/* Simulate a click on the first element */

	        XmListSelectPos(widgtab[DomainListID],1,TRUE);
		
/* Reinitialize the family and member lists and the global dev_filter */
	
		strcpy(dev_filter.dom," "); 
		strcpy(dev_filter.fam," ");	
		XmListDeleteAllItems(widgtab[FamilyListID]);
		XmListDeleteAllItems(widgtab[MemberListID]);
			
	        xsUnsetCursor(XtParent(XtParent(XtParent(w))));
	        xsUnsetCursor(widgtab[MainTextID]);
	        XFlush(XtDisplay(w));
		break;

	case ServSelFormID :
	        xsSetCursor(XtParent(XtParent(XtParent(w))), XC_watch);
	        xsSetCursor(widgtab[MainTextID], XC_watch);
	        XFlush(XtDisplay(w));
	        
/* Fill the Class list */
		
		XmListDeleteAllItems(widgtab[ClassListID]);
		if(db_getdsserverlist(&num,&str_tbl,&error))
		{
			strerr = dev_error_str(error);
			OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
	        	xsUnsetCursor(XtParent(XtParent(XtParent(w))));
	        	xsUnsetCursor(widgtab[MainTextID]);
	        	XFlush(XtDisplay(w));
		}
		xmstr_tbl = etxsXmStringTableCreate(str_tbl,num);
		for (i = 0;i < num;i++)
			free(str_tbl[i]);
		free(str_tbl);
	        XmListAddItems(widgtab[ClassListID],xmstr_tbl,num,0);
	        etxsXmStringTableFree(xmstr_tbl, num);
		
/* Simulate a click on the first element */

	        XmListSelectPos(widgtab[ClassListID],1,TRUE);
		
/* Reinitialize the Pname list and the global serv_filter */
	
		XmListDeleteAllItems(widgtab[PnameListID]);
		strcpy(serv_filter,"");
			 
	        xsUnsetCursor(XtParent(XtParent(XtParent(w))));
	        xsUnsetCursor(widgtab[MainTextID]);
	        XFlush(XtDisplay(w));
		break;
		
	case ResSelFormID :
	
/* The resource selection dialog domains list is filled once 
   for all in DataInitialization() . */
/* Reinitialize the global res_filter */
	
		strcpy(res_filter[0],""); 
		strcpy(res_filter[1],"");	
		strcpy(res_filter[2],"");
		
/* Clear the family, member and name lists */
	
		XmListDeleteAllItems(widgtab[ResFamListID]);
		XmListDeleteAllItems(widgtab[ResMembListID]);
		XmListDeleteAllItems(widgtab[ResNameListID]);
		
/* Unselect dom list, and clear Filter Text Field */

		XmListDeselectAllItems(widgtab[ResDomListID]);
		XmTextFieldSetString(widgtab[ResFilterTFID], "");
		break;
		
	case DevDelOpFormID :

/* Initialize the radiobox dialog with the boolean global value */

		XmToggleButtonSetState( widgtab[DevDelWResTBID], True, True );
		break;
		
	case ServDelOpFormID :
	
/* Initialize the radiobox dialog with the boolean global value */

		XmToggleButtonSetState( widgtab[ServDelWResTBID], True, True );
		break;
		
	case PrintFormID :
		XmTextFieldSetString(widgtab[A2psOptionsTextFID],
							print_a2ps_options);
		XmTextFieldSetString(widgtab[LpOptionsTextFID], print_lp_options);
		break;
		
	case ServRestartBoxID :

/* Get mandatory parameters from global structures */

		if (dev_dc_flag == GR_DEV_DC)
		{
			pid = dev_dc_tab[device_to_restart]->pid;
			strcpy(host,dev_dc_tab[device_to_restart]->host_name);
			strcpy(proc,dev_dc_tab[device_to_restart]->proc_name);
			strcpy(pers,dev_dc_tab[device_to_restart]->pers_name);
			strcpy(dev,dev_dc_tab[device_to_restart]->devname);
			exported = dev_dc_tab[device_to_restart]->exported;
		}
		else if (dev_dc_flag == GR_DEV)
		{
			pid = dev_tab[device_to_restart]->pid;
			strcpy(host,dev_tab[device_to_restart]->host_name);
			strcpy(proc,dev_tab[device_to_restart]->proc_name);
			strcpy(pers,dev_tab[device_to_restart]->pers_name);
			strcpy(dev,dev_tab[device_to_restart]->devname);
			exported = dev_tab[device_to_restart]->exported;
		}
		else
		{
			pid = serv_tab[server_to_restart]->pid;
			strcpy(host,serv_tab[server_to_restart]->host_name);
			strcpy(proc,serv_tab[server_to_restart]->proc_name);
			strcpy(pers,serv_tab[server_to_restart]->pers_name);
		}
		
/* Refuse to restart device if we don't know the necessary info */
		
		if ((pid == 0) || (host[0] == '\0') || (proc[0] == '\0') || (strcmp(proc,"unknown") == 0) || (pers[0] == '\0'))
		{
			strcpy(messerr,"Can't restart device server\n");
			strcat(messerr,"Missing info because device server is too old \n");
			strcat(messerr,"Hint: Relink it with new device server libraries\n");
			OpenMsgBox(widgtab[ErrorBoxID],messerr);
			return;
		}

/* Refuse to restart restart device or starter server */

		if (dev_dc_flag == GR_SERV)
		{
			tmp = strchr(serv_tab[server_to_restart]->servname,'/');
			diff = (unsigned long)(tmp - serv_tab[server_to_restart]->servname);
			strncpy(tmp_dev,serv_tab[server_to_restart]->servname,diff);
			tmp_dev[diff] = '\0';

			if (strcmp(tmp_dev,"starter") == 0)
			{
				strcpy(messerr,"Can't restart Starter device server !!!\n");
				OpenMsgBox(widgtab[ErrorBoxID],messerr);
				return;
			}
		}
		else
		{		
			tmp = strrchr(dev,'/');
			diff = (unsigned long)(tmp - dev);
			strncpy(tmp_dev,dev,diff);
			tmp_dev[diff] = '\0';
		
			if (strcmp(tmp_dev,"sys/start") == 0)
			{
				strcpy(messerr,"Cant restart restart device !!!!!!\n");
				OpenMsgBox(widgtab[ErrorBoxID],messerr);
				return;
			}
		}
		break;		
	}
	XtManageChild(widgtab[index]);
}





void DbInfoCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char *strerr;
	DevLong error;
	long size;
	db_stat_call inf;
	char tmp[80];
	char *disp_str;
	long i,j,l;
	time_t sec;
	char *ti;
 
	xsSetCursor(XtParent(XtParent(XtParent(w))), XC_watch);
	xsSetCursor(widgtab[MainTextID], XC_watch);
	XFlush(XtDisplay(w));

/* Get db_info */

	if (db_stat(&inf,&error))
	{
		strerr = dev_error_str(error);
		OpenMsgBox(widgtab[ErrorBoxID],strerr);
		free(strerr);
		return;
	}

/* Get date */

	sec = time((time_t *)0);
	ti = ctime(&sec);

/* Convert domain name to upper case letter */

	for (i = 0;i < inf.dev_domain_nb;i++)
	{
		l = strlen(inf.dev_domain[i].dom_name);
		for (j = 0;j < l;j++)
			inf.dev_domain[i].dom_name[j] = toupper(inf.dev_domain[i].dom_name[j]);
	}
	for (i = 0;i < inf.res_domain_nb;i++)
	{
		l = strlen(inf.res_domain[i].dom_name);
		for (j = 0;j < l;j++)
			inf.res_domain[i].dom_name[j] = toupper(inf.res_domain[i].dom_name[j]);
	}

/* Allocate memory for the displayed string */

	size = 300 + (inf.dev_domain_nb * 30) + (inf.res_domain_nb * 40);
	if ((disp_str = (char *)malloc(size)) == NULL)
	{
		free(inf.dev_domain);
		free(inf.res_domain);
		OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory");
		return;
	}
		
/* Build the displayed string */

	sprintf(disp_str,"\t\t%s\n",ti);
	sprintf(tmp,"\t\tDEVICE STATISTICS\n\n");
	strcat(disp_str,tmp);
	
	sprintf(tmp,"%d devices are defined in database\n",inf.dev_defined);
	strcat(disp_str,tmp);
	sprintf(tmp,"%d of the defined devices are actually exported:\n",inf.dev_exported);
	strcat(disp_str,tmp);
	
	for (i = 0;i < inf.dev_domain_nb;i++)
	{
		sprintf(tmp,"%d for the %s domain\n",inf.dev_domain[i].dom_elt,inf.dev_domain[i].dom_name);
		strcat(disp_str,tmp);
	}
	sprintf(tmp,"%d pseudo devices are defined in the database\n",inf.psdev_defined);
	strcat(disp_str,tmp);
	
	sprintf(tmp,"\n\t\tRESOURCE STATISTICS\n\n");
	strcat(disp_str,tmp);
	sprintf(tmp,"%d resources are defined in database:\n",inf.res_number);
	strcat(disp_str,tmp);
	for (i = 0;i < inf.res_domain_nb;i++)
	{
		sprintf(tmp,"%d resources for the %s domain",inf.res_domain[i].dom_elt,inf.res_domain[i].dom_name);
		if (i != (inf.res_domain_nb - 1))
			strcat(tmp,"\n");
		strcat(disp_str,tmp);
	}

	
	XmTextSetString(widgtab[MainTextID], disp_str);
	
	free(disp_str);
	free(inf.res_domain);
	free(inf.dev_domain);
	 
	xsUnsetCursor(XtParent(XtParent(XtParent(w))));
	xsUnsetCursor(widgtab[MainTextID]);
	XFlush(XtDisplay(w));
}




void ServUpdateOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	long pass;
	
    	DevManageSecRes(w,(XtPointer)server_to_update,GR_SERV,&pass);
	
	if (pass == False)
		ServUpdateCb(w,(XtPointer)server_to_update,call_data);
}





void ServDismissCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    char s[256];
    int ind=(int)client_data;


    XtUnmanageChild(serv_tab[ind]->window);
    XtDestroyWidget(serv_tab[ind]->window);
    serv_remove(ind);
}





void OnVersionCb( Widget w, XtPointer client_data, XtPointer call_data)
{
     OpenMsgBox(widgtab[InfoBoxID], version_lb);
}





void PrepareDevDelCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char s[256];
 	int ind=(int)client_data;
    
/* Position the sdd.h variable device_to_delete */

    	device_to_delete=ind;
    
/* Set the Device Delete Dialog title */

    	sprintf(s,"Delete %s",dev_tab[ind]->devname);
    	xsSetTitle(widgtab[DevDelOpFormID], s);

}



void PrepareDevDcDelCb( Widget w, XtPointer client_data, XtPointer call_data)
{
 	char s[256];
 	int ind=(int)client_data;
    
/* Position the sdd.h variable device_to_delete */

    	device_to_delete = ind;
	dev_dc_flag = GR_DEV_DC;
    
/* Set the Device Delete Dialog title */

    	sprintf(s,"Delete %s",dev_dc_tab[ind]->devname);
    	xsSetTitle(widgtab[DevDelOpFormID], s);

}





void BoolOptionChangeCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    int    ind=(int)client_data;

    booloptab[ind]=!booloptab[ind];
    
/* Under Linux, the hdb library does not exist.*/

#ifdef linux
    booloptab[devdisplay_hdb] = False;
#endif
}



void DevUpdateOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	long pass;
	
    	DevManageSecRes(w,(XtPointer)device_to_update,dev_dc_flag,&pass);
	
	if (pass == False)
		DevUpdateCb(w,(XtPointer)device_to_update,call_data,dev_dc_flag);
}



void ResUpdateOKCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	long pass;
	
	DevManageSecRes(w,(XtPointer)respool_to_update,dev_dc_flag,&pass);
	
	if (pass == False)
    		ResUpdateCb(w,(XtPointer)respool_to_update,call_data);
}




void LoadUpdateCb( Widget w, XtPointer client_data, XtPointer call_data)
{
	long pass;

	dev_dc_flag = GR_LOAD;	
	DevManageSecRes(w,(XtPointer)0,GR_LOAD,&pass);
	
	if (pass == False)
    		LoadUpdate(w,(XtPointer)0,call_data);
}




void DevDeleteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   int ind=(int)client_data;

   XtFree(dev_tab[ind]->last_state);
   dev_tab[ind]->last_state = XmTextGetString(dev_tab[ind]->resotext);
   dev_tab[ind]->last_position =
                 XmTextGetInsertionPosition(dev_tab[ind]->resotext);   
   XmTextRemove(dev_tab[ind]->resotext);
}





void DevDcDeleteCb( Widget w, XtPointer client_data, XtPointer call_data)
{
   int ind=(int)client_data;

   XtFree(dev_dc_tab[ind]->last_state);
   dev_dc_tab[ind]->last_state = XmTextGetString(dev_dc_tab[ind]->resotext);
   dev_dc_tab[ind]->last_position = XmTextGetInsertionPosition(dev_dc_tab[ind]->resotext);   
   XmTextRemove(dev_dc_tab[ind]->resotext);
}



/****************************************************************************
                                                                           
 Function     : void DevSaveAsCb()

 Description  : callback attached to "Save" pushbuttons in the FileSelectionBox
                Dialog window. This function gets the pathname of the file
                to save in and then calls the "DevSaveCb" to do the save
                operation.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void DevSaveAsCb( Widget w, XtPointer client_data, XtPointer call_data)
{

   XmFileSelectionBoxCallbackStruct    *file_sel_cbs;
   int                                 dev_index;
   Boolean                             ret_val;
   char                                *fname_value=NULL;  
   Widget                              save_pb_w;

   file_sel_cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
   dev_index = (int) client_data;

   ret_val = XmStringGetLtoR(file_sel_cbs->value, XmFONTLIST_DEFAULT_TAG,
                                                  &fname_value);

   if (ret_val == True)
   {
      if (dev_tab[dev_index]->dev_save_pathname != NULL) 
      {
         free(dev_tab[dev_index]->dev_save_pathname);
         dev_tab[dev_index]->dev_save_pathname = NULL;
      }
      else
      {
         save_pb_w = NULL;
         save_pb_w = XtNameToWidget( dev_tab[dev_index]->window, "*devSavePB");
         if (save_pb_w != NULL)
            XtVaSetValues(save_pb_w, XmNsensitive, True, NULL);
      }

      dev_tab[dev_index]->dev_save_pathname = (char *)
                                              malloc( strlen(fname_value) + 1);
      strcpy(dev_tab[dev_index]->dev_save_pathname, fname_value);
      XtFree(fname_value);
   }

   DevSaveCb(w, client_data, call_data);

}





/****************************************************************************
                                                                           
 Function     : void DevDcSaveAsCb()

 Description  : callback attached to "Save" pushbuttons in the FileSelectionBox
                Dialog window. This function gets the pathname of the file
                to save in and then calls the "DevSaveCb" to do the save
                operation.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void DevDcSaveAsCb( Widget w, XtPointer client_data, XtPointer call_data)
{

   XmFileSelectionBoxCallbackStruct    *file_sel_cbs;
   int                                 dev_index;
   Boolean                             ret_val;
   char                                *fname_value=NULL;  
   Widget                              save_pb_w;

   file_sel_cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
   dev_index = (int) client_data;

   ret_val = XmStringGetLtoR(file_sel_cbs->value, XmFONTLIST_DEFAULT_TAG,
                                                  &fname_value);

   if (ret_val == True)
   {
      if (dev_dc_tab[dev_index]->dev_save_pathname != NULL) 
      {
         free(dev_dc_tab[dev_index]->dev_save_pathname);
         dev_dc_tab[dev_index]->dev_save_pathname = NULL;
      }
      else
      {
         save_pb_w = NULL;
         save_pb_w = XtNameToWidget( dev_dc_tab[dev_index]->window, "*devDcSavePB");
         if (save_pb_w != NULL)
            XtVaSetValues(save_pb_w, XmNsensitive, True, NULL);
      }

      dev_dc_tab[dev_index]->dev_save_pathname = (char *)
                                              malloc( strlen(fname_value) + 1);
      strcpy(dev_dc_tab[dev_index]->dev_save_pathname, fname_value);
      XtFree(fname_value);
   }

   DevDcSaveCb(w, client_data, call_data);

}




/****************************************************************************
                                                                           
 Function     : void ResSaveAsCb()

 Description  : callback attached to "Save" pushbuttons in the FileSelectionBox
                Dialog window. This function gets the pathname of the file
                to save in and then calls the "ResSaveCb" to do the save
                operation.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the resource window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void ResSaveAsCb( Widget w, XtPointer client_data, XtPointer call_data)
{

   XmFileSelectionBoxCallbackStruct    *file_sel_cbs;
   int                                 res_index;
   Boolean                             ret_val;
   char                                *fname_value=NULL;  
   Widget                              save_pb_w;

   file_sel_cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
   res_index = (int) client_data;

   ret_val = XmStringGetLtoR(file_sel_cbs->value, XmFONTLIST_DEFAULT_TAG,
                                                  &fname_value);

   if (ret_val == True)
   {
      if (gr_res_tab[res_index]->res_save_pathname != NULL) 
      {
         free(gr_res_tab[res_index]->res_save_pathname);
         gr_res_tab[res_index]->res_save_pathname = NULL;
      }
      else
      {
         save_pb_w = NULL;
         save_pb_w = XtNameToWidget( gr_res_tab[res_index]->window, "*resSavePB");
         if (save_pb_w != NULL)
            XtVaSetValues(save_pb_w, XmNsensitive, True, NULL);
      }

      gr_res_tab[res_index]->res_save_pathname = (char *)
                                              malloc( strlen(fname_value) + 1);
      strcpy(gr_res_tab[res_index]->res_save_pathname, fname_value);
      XtFree(fname_value);
   }

   ResSaveCb(w, client_data, call_data);

}











/****************************************************************************
                                                                           
 Function     : void ServSaveAsCb()

 Description  : callback attached to "Save" pushbuttons in the FileSelectionBox
                Dialog window. This function gets the pathname of the file
                to save in and then calls the "ServSaveCb" to do the save
                operation.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the server window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void ServSaveAsCb( Widget w, XtPointer client_data, XtPointer call_data)
{

   XmFileSelectionBoxCallbackStruct    *file_sel_cbs;
   int                                 serv_index;
   Boolean                             ret_val;
   char                                *fname_value=NULL;  
   Widget                              save_pb_w;

   file_sel_cbs = (XmFileSelectionBoxCallbackStruct *) call_data;
   serv_index = (int) client_data;

   ret_val = XmStringGetLtoR(file_sel_cbs->value, XmFONTLIST_DEFAULT_TAG,
                                                  &fname_value);

   if (ret_val == True)
   {
      if (serv_tab[serv_index]->serv_save_pathname != NULL) 
      {
         free(serv_tab[serv_index]->serv_save_pathname);
         serv_tab[serv_index]->serv_save_pathname = NULL;
      }
      else
      {
         save_pb_w = NULL;
         save_pb_w = XtNameToWidget( serv_tab[serv_index]->window,
                                                         "*servSavePB");
         if (save_pb_w != NULL)
            XtVaSetValues(save_pb_w, XmNsensitive, True, NULL);
      }

      serv_tab[serv_index]->serv_save_pathname = (char *)
                                              malloc( strlen(fname_value) + 1);
      strcpy(serv_tab[serv_index]->serv_save_pathname, fname_value);
      XtFree(fname_value);
   }

   ServSaveCb(w, client_data, call_data);

}








/****************************************************************************
                                                                           
 Function     : void DevSaveShowFileSelCb()

 Description  : callback attached to "Save As ..." pushbuttons in the
                "File" pulldown menu inside "Device Window"s. This function
                will update the title of the FileSelectionDialog according to
                the Device Window title; adds the appropriate callbacks to
                the OK button of the FileSelectionDialog window, updates dir
                filter according to the saved file name (if any) and then
                pops up this dialog window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void DevSaveShowFileSelCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    int        dev_window_index;
    Widget     dev_window;
    char       *title_str;
    char       FileSelTitle[301], dir_name[501];
    char       *file_name, *last_slash;
    XmString   title_xms, dir_mask_xms;
    int        dir_nb_chars;

    dev_window_index = (int) client_data;

    dev_window = dev_tab[dev_window_index]->window;
    title_str = xsGetDialogTitle (dev_window);

    if (title_str == NULL)
       strcpy(FileSelTitle, "None");
    else
    {
       strcpy(FileSelTitle, "SAVE  :  ");
       strcat(FileSelTitle, title_str);
       XtFree(title_str);
    }

    title_xms = XmStringCreateLocalized(FileSelTitle);
    XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdialogTitle, title_xms, NULL);
    XmStringFree(title_xms);
    XtRemoveCallbacks(widgtab[SaveFileSelBoxID], XmNokCallback,
                                            (XtCallbackList) FileSelOkCbList);
    XtAddCallback(widgtab[SaveFileSelBoxID], XmNokCallback,
                                             DevSaveAsCb, client_data);

    file_name = dev_tab[dev_window_index]->dev_save_pathname;
    if (file_name != NULL)
    {
       last_slash = strrchr(file_name, '/');
       dir_nb_chars = strlen(file_name) - strlen(last_slash);
       dir_name[0] = '\0';

       if (dir_nb_chars != 0)
       {
          strncpy(dir_name, file_name, dir_nb_chars);
          dir_name[dir_nb_chars] = '\0';
       }

       strcat(dir_name, "/");
       strcat(dir_name, "*.res");

       dir_mask_xms = XmStringCreateLocalized(dir_name);

       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }
    else
    {
       strcpy(dir_name, "/tmp/");
       strcat(dir_name, "*.res");
       dir_mask_xms = XmStringCreateLocalized(dir_name);
       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }

    XtManageChild(widgtab[SaveFileSelBoxID]);

}





/****************************************************************************
                                                                           
 Function     : void DevDcSaveShowFileSelCb()

 Description  : callback attached to "Save As ..." pushbuttons in the
                "File" pulldown menu inside "Device Window"s. This function
                will update the title of the FileSelectionDialog according to
                the Device Window title; adds the appropriate callbacks to
                the OK button of the FileSelectionDialog window, updates dir
                filter according to the saved file name (if any) and then
                pops up this dialog window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void DevDcSaveShowFileSelCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    int        dev_window_index;
    Widget     dev_window;
    char       *title_str;
    char       FileSelTitle[301], dir_name[501];
    char       *file_name, *last_slash;
    XmString   title_xms, dir_mask_xms;
    int        dir_nb_chars;

    dev_window_index = (int) client_data;

    dev_window = dev_dc_tab[dev_window_index]->window;
    title_str = xsGetDialogTitle (dev_window);

    if (title_str == NULL)
       strcpy(FileSelTitle, "None");
    else
    {
       strcpy(FileSelTitle, "SAVE  :  ");
       strcat(FileSelTitle, title_str);
       XtFree(title_str);
    }

    title_xms = XmStringCreateLocalized(FileSelTitle);
    XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdialogTitle, title_xms, NULL);
    XmStringFree(title_xms);
    XtRemoveCallbacks(widgtab[SaveFileSelBoxID], XmNokCallback,
                                            (XtCallbackList) FileSelOkCbList);
    XtAddCallback(widgtab[SaveFileSelBoxID], XmNokCallback,
                                             DevDcSaveAsCb, client_data);

    file_name = dev_dc_tab[dev_window_index]->dev_save_pathname;
    if (file_name != NULL)
    {
       last_slash = strrchr(file_name, '/');
       dir_nb_chars = strlen(file_name) - strlen(last_slash);
       dir_name[0] = '\0';

       if (dir_nb_chars != 0)
       {
          strncpy(dir_name, file_name, dir_nb_chars);
          dir_name[dir_nb_chars] = '\0';
       }

       strcat(dir_name, "/");
       strcat(dir_name, "*.res");

       dir_mask_xms = XmStringCreateLocalized(dir_name);

       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }
    else
    {
       strcpy(dir_name, "/tmp/");
       strcat(dir_name, "*.res");
       dir_mask_xms = XmStringCreateLocalized(dir_name);
       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }

    XtManageChild(widgtab[SaveFileSelBoxID]);

}








/****************************************************************************
                                                                           
 Function     : void ResSaveShowFileSelCb()

 Description  : callback attached to "Save As ..." pushbuttons in the
                "File" pulldown menu inside "Resource Window"s. This function
                will update the title of the FileSelectionDialog according to
                the Resource Window title; adds the appropriate callbacks to
                the OK button of the FileSelectionDialog window, updates dir
                filter according to the saved file name (if any) and then
                pops up this dialog window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the resource window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void ResSaveShowFileSelCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    int        res_window_index;
    Widget     res_window;
    char       *title_str;
    char       FileSelTitle[301], dir_name[501];
    char       *file_name, *last_slash;
    XmString   title_xms, dir_mask_xms;
    int        dir_nb_chars;

    res_window_index = (int) client_data;

    res_window = gr_res_tab[res_window_index]->window;
    title_str = xsGetDialogTitle (res_window);

    if (title_str == NULL)
       strcpy(FileSelTitle, "None");
    else
    {
       strcpy(FileSelTitle, "SAVE  :  ");
       strcat(FileSelTitle, title_str);
       XtFree(title_str);
    }

    title_xms = XmStringCreateLocalized(FileSelTitle);
    XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdialogTitle, title_xms, NULL);
    XmStringFree(title_xms);
    XtRemoveCallbacks(widgtab[SaveFileSelBoxID], XmNokCallback,
                                            (XtCallbackList) FileSelOkCbList);
    XtAddCallback(widgtab[SaveFileSelBoxID], XmNokCallback,
                                             ResSaveAsCb, client_data);

    file_name = gr_res_tab[res_window_index]->res_save_pathname;
    if (file_name != NULL)
    {
       last_slash = strrchr(file_name, '/');
       dir_nb_chars = strlen(file_name) - strlen(last_slash);
       dir_name[0] = '\0';

       if (dir_nb_chars != 0)
       {
          strncpy(dir_name, file_name, dir_nb_chars);
          dir_name[dir_nb_chars] = '\0';
       }

       strcat(dir_name, "/");
       strcat(dir_name, "*.res");

       dir_mask_xms = XmStringCreateLocalized(dir_name);

       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }
    else
    {
       strcpy(dir_name, "/tmp/");
       strcat(dir_name, "*.res");
       dir_mask_xms = XmStringCreateLocalized(dir_name);
       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }

    XtManageChild(widgtab[SaveFileSelBoxID]);

}








/****************************************************************************
                                                                           
 Function     : void ServSaveShowFileSelCb()

 Description  : callback attached to "Save As ..." pushbuttons in the
                "File" pulldown menu inside "Server Window"s. This function
                will update the title of the FileSelectionDialog according to
                the Server Window title; adds the appropriate callbacks to
                the OK button of the FileSelectionDialog window, updates dir
                filter according to the saved file name (if any) and then
                pops up this dialog window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the server window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void ServSaveShowFileSelCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    int        serv_window_index;
    Widget     serv_window;
    char       *title_str;
    char       FileSelTitle[301], dir_name[501];
    char       *file_name, *last_slash;
    XmString   title_xms, dir_mask_xms;
    int        dir_nb_chars;

    serv_window_index = (int) client_data;

    serv_window = serv_tab[serv_window_index]->window;
    title_str = xsGetDialogTitle (serv_window);

    if (title_str == NULL)
       strcpy(FileSelTitle, "None");
    else
    {
       strcpy(FileSelTitle, "SAVE  :  ");
       strcat(FileSelTitle, title_str);
       XtFree(title_str);
    }

    title_xms = XmStringCreateLocalized(FileSelTitle);
    XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdialogTitle, title_xms, NULL);
    XmStringFree(title_xms);
    XtRemoveCallbacks(widgtab[SaveFileSelBoxID], XmNokCallback,
                                            (XtCallbackList) FileSelOkCbList);
    XtAddCallback(widgtab[SaveFileSelBoxID], XmNokCallback,
                                             ServSaveAsCb, client_data);

    file_name = serv_tab[serv_window_index]->serv_save_pathname;
    if (file_name != NULL)
    {
       last_slash = strrchr(file_name, '/');
       dir_nb_chars = strlen(file_name) - strlen(last_slash);
       dir_name[0] = '\0';

       if (dir_nb_chars != 0)
       {
          strncpy(dir_name, file_name, dir_nb_chars);
          dir_name[dir_nb_chars] = '\0';
       }

       strcat(dir_name, "/");
       strcat(dir_name, "*.res");

       dir_mask_xms = XmStringCreateLocalized(dir_name);

       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }
    else
    {
       strcpy(dir_name, "/tmp/");
       strcat(dir_name, "*.res");
       dir_mask_xms = XmStringCreateLocalized(dir_name);
       XtVaSetValues(widgtab[SaveFileSelBoxID], XmNdirMask, dir_mask_xms, NULL);
       XmStringFree(dir_mask_xms);
    }

    XtManageChild(widgtab[SaveFileSelBoxID]);

}






/*****************************************************************************
 *
 *                          DataInitialization :
 *                          ------------------
 *
 *    Called by the main after the end of all the creations and before the
 *    MainLoop : widgtab is thus completely initialized .
 *    definitive but programmatically found contents and the following
 *    various resources settings are done here
 *
 ****************************************************************************/

void DataInitialization()
{
 	XmString *xmstr_tbl;
 	char **dom_list;
 	long dom_nb,i;
 	DevLong error;
 	db_resource res[10];
 	int rcnt;
 	int ind_dev_serv_res, ind_cb;
	
/* Database boolean options which haven't been set during creation of their
   toggle button */

	booloptab[servdisplay_classresID] = False;
	booloptab[servdisplay_embedded] = False;
	booloptab[devdisplay_dc] = False;
	booloptab[devdisplay_hdb] = False;

/* Print options resources */

	rcnt=0;
	res[rcnt].resource_name = "a2ps_options";
	res[rcnt].resource_type=D_STRING_TYPE;
	res[rcnt].resource_adr=&print_a2ps_options;
	rcnt++;
	res[rcnt].resource_name = "lp_options";
	res[rcnt].resource_type=D_STRING_TYPE;
	res[rcnt].resource_adr=&print_lp_options;
	rcnt++;

	if (db_getresource("sys/greta/print", res, rcnt, &error))
	{
		fprintf(stderr, "greta : DataInitialization : db_getresource failed \
finding \nthe sys/greta/print/ resources : a2ps_options and lp_options .\n");
		exit(0);
	}

/* Init the resource selection dialog domains list */

	if (db_getresdomainlist(&dom_nb,&dom_list,&error))
	{
		free(print_a2ps_options);
		free(print_lp_options);
		exit(0);
	}
	xmstr_tbl = etxsXmStringTableCreate(dom_list,dom_nb);
	for (i = 0;i < dom_nb;i++)
		free(dom_list[i]);
	free(dom_list);
	XmListAddItems(widgtab[ResDomListID],xmstr_tbl,dom_nb,0);
	etxsXmStringTableFree(xmstr_tbl, dom_nb);

/* The callback list is initialized here */

        FileSelOkCbList = (XtCallbackRec *)malloc(sizeof(XtCallbackRec) * TAB_SIZE * 4);
        ind_cb = 0;

        for (ind_dev_serv_res = 0 ; ind_dev_serv_res < TAB_SIZE; ind_dev_serv_res++)
        {
            FileSelOkCbList[ind_cb].callback = (XtCallbackProc) DevSaveAsCb;
            FileSelOkCbList[ind_cb].closure = (XtPointer) ind_dev_serv_res;
            ind_cb++;
        };

        for (ind_dev_serv_res = 0 ; ind_dev_serv_res < TAB_SIZE; ind_dev_serv_res++)
        {
            FileSelOkCbList[ind_cb].callback = (XtCallbackProc) ResSaveAsCb;
            FileSelOkCbList[ind_cb].closure = (XtPointer) ind_dev_serv_res;
            ind_cb++;
        };

        for (ind_dev_serv_res = 0 ; ind_dev_serv_res < TAB_SIZE; ind_dev_serv_res++)
        {
            FileSelOkCbList[ind_cb].callback = (XtCallbackProc) ServSaveAsCb;
            FileSelOkCbList[ind_cb].closure = (XtPointer) ind_dev_serv_res;
            ind_cb++;
        };
	
        for (ind_dev_serv_res = 0 ; ind_dev_serv_res < TAB_SIZE; ind_dev_serv_res++)
        {
            FileSelOkCbList[ind_cb].callback = (XtCallbackProc) DevDcSaveAsCb;
            FileSelOkCbList[ind_cb].closure = (XtPointer) ind_dev_serv_res;
            ind_cb++;
        };
		
/* Extern variables for devices and servers windows from _sdd initialization */
	
	init_dev_index();
	init_dev_dc_index();
	init_serv_index();
	init_res_index();
	
/* global variables for the UndoCb */

 	last_state=(char *)XmTextGetString(widgtab[MainTextID]);
	last_cursor_position=
			(XmTextPosition)XmTextGetInsertionPosition(widgtab[MainTextID]);

/* contents of OnVersion Help Dialog string = current version nb */

	version_lb= (char *)arg_version();

/* pid of the current application instanciation : used to make files names
   unique, no matter how many greta are running simultaneously */ 

	pid=getpid();
	
}








/****************************************************************************
                                                                           
 Function     : void DevChainResCb()

 Description  : callback attached to "Chain device resources" pushbuttons in
                the edit pulldown menus of the device Dialog windows. This
                function gets the device name selected inside the device
                resource window. Tries to get the resources associated with that
                device. If succeeded these resources are added into the device
                window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void DevChainResCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    	char             *selected_dev;
    	int              ind_dev = (int) client_data;
    	char             chainefile[1001];
    	char             *info_str, *reso_str, *strerr, s[1001];
    	int              resu;
    	XmTextPosition   cur_posit;
    	int              ind_ch, dev_found, free_place;
	long		 num,i,l;
	DevLong		 error;
	char 		 **res_array;

    	selected_dev = NULL;

    	selected_dev = XmTextGetSelection (dev_tab[ind_dev]->resotext);

    	if (selected_dev != NULL)
    	{
		xsSetCursor(dev_tab[ind_dev]->window,XC_watch);
		XFlush(XtDisplay(w));

		l = strlen(selected_dev);
		for (i = 0;i < l;i++)
			selected_dev[i] = tolower(selected_dev[i]);
					
       		if (strcasecmp(selected_dev, dev_tab[ind_dev]->devname) == 0)
       		{
          		sprintf(s,"Cannot add the resources for the device %s.\n\n");
          		strcat(s, "This is the initial device for which this window ");
          		strcat(s, "has been opened.\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
       		}

/*** Check that the device has not been chained already ***/

       		ind_ch = 0;
       		dev_found = False;
       		while ( (ind_ch < CH_TAB_SIZE) && (dev_found == False) )
       		{
          		if ((dev_tab[ind_dev]->chaine_dev_arr)[ind_ch] != NULL)
			{
             			if ( strcasecmp ((dev_tab[ind_dev]->chaine_dev_arr)[ind_ch],
                              			  selected_dev) == 0 )
                			dev_found = True;
             			else
                			ind_ch++;
			}
          		else
             			ind_ch++;
       		}

       		if (dev_found == True)
       		{
          		sprintf(s,"The device %s has already been chained in this window.\n\n", selected_dev);
          		strcat(s, "If you want to repeat this operation, open another window\n");
          		strcat(s, "for ");
          		strcat(s, dev_tab[ind_dev]->devname);
          		strcat(s, " and then chaine ");
          		strcat(s, selected_dev);
          		strcat(s, " .\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
       		}

/* Get device resource */

       		reso_str = NULL;
       		if (db_deviceres(1,&selected_dev,&num,&res_array,&error))
       		{
			strerr = dev_error_str(error);
               		OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
               		XtFree(selected_dev);
			xsUnsetCursor(dev_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
               		return;
		}

/* Happy end : resu = NO_RESOURCE or NO_PROBLEM */
       
       		if (num == 0)
       		{
          		sprintf(s,"The device %s has no resources yet.\n", selected_dev);
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		if (reso_str != NULL)
				free(reso_str);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
       		}

/* Build the string in Motif style */

		if (xsCreateStringForText(res_array,num,&reso_str))
		{
			for (i = 0;i < num;i++)
				free(res_array[i]);
			free(res_array);
          		sprintf(s,"Can't allocate memory\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
		}
		
/*** Add the device into the array of the chained devices ***/

       		ind_ch = 0;
     		free_place = False;
       		while ( (ind_ch < CH_TAB_SIZE) && (free_place == False) )
       		{
          		if ((dev_tab[ind_dev]->chaine_dev_arr)[ind_ch] == NULL)
             			free_place = True;
          		else
             			ind_ch++;
       		}

       		if (free_place == True)
		{
          		(dev_tab[ind_dev]->chaine_dev_arr)[ind_ch] = strdup(selected_dev);
			(dev_tab[ind_dev]->chaine_res_nb)[ind_ch] = num;
		}
			
/*** A comment to add to separate the chained device resources  ***/
/*** from the rest of the window contents.                      ***/

       		sprintf(s, "\n#\n####  Resources related to %s  ####\n#\n",
                  	selected_dev);
       		cur_posit = XmTextGetLastPosition (dev_tab[ind_dev]->resotext);
       		XmTextInsert(dev_tab[ind_dev]->resotext, cur_posit, s);

/**** Concatenate at the end of the file associated to the device ***/
/**** the chained resources retrieved.***/
       
       		sprintf(chainefile, "/tmp/greta%d_DevChaine.res", pid);
       		devresfile_create(chainefile, reso_str);
		if (file_concat(chainefile,dev_tab[ind_dev]->file) == -1)
		{
			for (i = 0;i < num;i++)
				free(res_array[i]);
			free(res_array);
          		sprintf(s,"Can't open temporary file\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
		}
       		remove(chainefile);

/**** Add the new chained resources in the resource window     ****/
/**** associated with the device.                              ****/
       
       		cur_posit = XmTextGetLastPosition (dev_tab[ind_dev]->resotext);
       		XmTextInsert(dev_tab[ind_dev]->resotext, cur_posit, reso_str);

       		cur_posit = XmTextGetLastPosition (dev_tab[ind_dev]->resotext);
       		XmTextShowPosition(dev_tab[ind_dev]->resotext, cur_posit);

		xsUnsetCursor(dev_tab[ind_dev]->window);
		XFlush(XtDisplay(w));
		
       		if (reso_str != NULL) 
			free(reso_str);
		for (i = 0;i < num;i++)
			free(res_array[i]);
		free(res_array);
       		XtFree(selected_dev);

    	} /*** if (selected_dev != NULL) ***/
}




/****************************************************************************
                                                                           
 Function     : void DevChainResCb()

 Description  : callback attached to "Chain device resources" pushbuttons in
                the edit pulldown menus of the device with Dc Dialog windows.
                This function gets the device name selected inside the device
                resource window. Tries to get the resources associated with that
                device. If succeeded these resources are added into the device
                window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void DevDcChainResCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    	char             *selected_dev;
    	int              ind_dev = (int) client_data;
    	char             chainefile[1001];
    	char             *info_str, *reso_str, *strerr, s[1001];
    	int              resu;
    	XmTextPosition   cur_posit;
    	int              ind_ch, dev_found, free_place;
	long		 num,i,l;
	DevLong		 error;
	char 		 **res_array;

    	selected_dev = NULL;

    	selected_dev = XmTextGetSelection (dev_dc_tab[ind_dev]->resotext);

    	if (selected_dev != NULL)
    	{
		xsSetCursor(dev_dc_tab[ind_dev]->window,XC_watch);
		XFlush(XtDisplay(w));
		
		l = strlen(selected_dev);
		for (i = 0;i < l;i++)
			selected_dev[i] = tolower(selected_dev[i]);
					
       		if (strcasecmp(selected_dev, dev_dc_tab[ind_dev]->devname) == 0)
       		{
          		sprintf(s,"Cannot add the resources for the device %s.\n\n");
          		strcat(s, "This is the initial device for which this window ");
          		strcat(s, "has been opened.\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_dc_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
       		}

/*** Check that the device has not been chained already ***/

       		ind_ch = 0;
       		dev_found = False;
       		while ( (ind_ch < CH_TAB_SIZE) && (dev_found == False) )
       		{
          		if ((dev_dc_tab[ind_dev]->chaine_dev_arr)[ind_ch] != NULL)
			{
             			if ( strcasecmp ((dev_dc_tab[ind_dev]->chaine_dev_arr)[ind_ch],
                              			  selected_dev) == 0 )
                			dev_found = True;
             			else
                			ind_ch++;
			}
          		else
             			ind_ch++;
       		}

       		if (dev_found == True)
       		{
          		sprintf(s,"The device %s has already been chained in this window.\n\n", selected_dev);
          		strcat(s, "If you want to repeat this operation, open another window\n");
          		strcat(s, "for ");
          		strcat(s, dev_dc_tab[ind_dev]->devname);
          		strcat(s, " and then chaine ");
          		strcat(s, selected_dev);
          		strcat(s, " .\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_dc_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
       		}

/* Get device resource */

       		reso_str = NULL;
       		if (db_deviceres(1,&selected_dev,&num,&res_array,&error))
       		{
			strerr = dev_error_str(error);
               		OpenMsgBox(widgtab[ErrorBoxID], strerr);
			free(strerr);
               		XtFree(selected_dev);
			xsUnsetCursor(dev_dc_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
               		return;
		}

/* Happy end : resu = NO_RESOURCE or NO_PROBLEM */
       
       		if (num == 0)
       		{
          		sprintf(s,"The device %s has no resources yet.\n", selected_dev);
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		if (reso_str != NULL)
				free(reso_str);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_dc_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
       		}

/* Build the string in Motif style */

		if (xsCreateStringForText(res_array,num,&reso_str))
		{
			for (i = 0;i < num;i++)
				free(res_array[i]);
			free(res_array);
          		sprintf(s,"Can't allocate memory\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_dc_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
		}
		
/*** Add the device into the array of the chained devices ***/

       		ind_ch = 0;
     		free_place = False;
       		while ( (ind_ch < CH_TAB_SIZE) && (free_place == False) )
       		{
          		if ((dev_dc_tab[ind_dev]->chaine_dev_arr)[ind_ch] == NULL)
             			free_place = True;
          		else
             			ind_ch++;
       		}

       		if (free_place == True)
		{
          		(dev_dc_tab[ind_dev]->chaine_dev_arr)[ind_ch] = strdup(selected_dev);
			(dev_dc_tab[ind_dev]->chaine_res_nb)[ind_ch] = num;
		}
			
/*** A comment to add to separate the chained device resources  ***/
/*** from the rest of the window contents.                      ***/

       		sprintf(s, "\n#\n####  Resources related to %s  ####\n#\n",
                  	selected_dev);
       		cur_posit = XmTextGetLastPosition (dev_dc_tab[ind_dev]->resotext);
       		XmTextInsert(dev_dc_tab[ind_dev]->resotext, cur_posit, s);

/**** Concatenate at the end of the file associated to the device ***/
/**** the chained resources retrieved.***/
       
       		sprintf(chainefile, "/tmp/greta%d_DevChaine.res", pid);
       		devresfile_create(chainefile, reso_str);
		if (file_concat(chainefile,dev_dc_tab[ind_dev]->file) == -1)
		{
			for (i = 0;i < num;i++)
				free(res_array[i]);
			free(res_array);
          		sprintf(s,"Can't open temporary file\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(dev_dc_tab[ind_dev]->window);
			XFlush(XtDisplay(w));
          		return;
		}
       		remove(chainefile);

/**** Add the new chained resources in the resource window     ****/
/**** associated with the device.                              ****/
       
       		cur_posit = XmTextGetLastPosition (dev_dc_tab[ind_dev]->resotext);
       		XmTextInsert(dev_dc_tab[ind_dev]->resotext, cur_posit, reso_str);

       		cur_posit = XmTextGetLastPosition (dev_dc_tab[ind_dev]->resotext);
       		XmTextShowPosition(dev_dc_tab[ind_dev]->resotext, cur_posit);

		xsUnsetCursor(dev_dc_tab[ind_dev]->window);
		XFlush(XtDisplay(w));
		
       		if (reso_str != NULL) 
			free(reso_str);
		for (i = 0;i < num;i++)
			free(res_array[i]);
		free(res_array);
       		XtFree(selected_dev);

    	} /*** if (selected_dev != NULL) ***/
}




/****************************************************************************
                                                                           
 Function     : void dev_reso_text_event_hand()

 Description  : the event handler attached to "resotext" Text Widget in
                the device Dialog windows. This handles the right button click
                to be a short cut to the DevChainResCb function.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XEvent      *event      : the buttonPress event which triggered
                                          the event handler
                Boolean     *continue_to_dispatch : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/


void dev_reso_text_event_hand( Widget w, XtPointer client_data,
                                         XEvent    *event,
                                         Boolean   *continue_to_dispatch)
{
    XButtonEvent     but_evt;
    char             *selected_dev;
    int              ind_dev = (int) client_data;

    selected_dev = NULL;

    if (event->type != ButtonPress)
       return;

    but_evt = event->xbutton;

    if (but_evt.button != Button3)
       return;

    DevChainResCb(w, client_data, NULL);
}







/****************************************************************************
                                                                           
 Function     : void devdc_reso_text_event_hand()

 Description  : the event handler attached to "resotext" Text Widget in
                the device/dc Dialog windows. This handles the right button click
                to be a short cut to the DevChainResCb function.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XEvent      *event      : the buttonPress event which triggered
                                          the event handler
                Boolean     *continue_to_dispatch : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/


void devdc_reso_text_event_hand( Widget w, XtPointer client_data,
                                         XEvent    *event,
                                         Boolean   *continue_to_dispatch)
{
    XButtonEvent     but_evt;
    char             *selected_dev;
    int              ind_dev = (int) client_data;

    selected_dev = NULL;

    if (event->type != ButtonPress)
       return;

    but_evt = event->xbutton;

    if (but_evt.button != Button3)
       return;

    DevDcChainResCb(w, client_data, NULL);
}







/****************************************************************************
                                                                           
 Function     : void ServChainResCb()

 Description  : callback attached to "Chain device resources" pushbuttons in
                the edit pulldown menus of the server Dialog windows. This
                function gets the device name selected inside the server
                resource window. Tries to get the resources associated with that
                device. If succeeded these resources are added into the server
                window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the device window
                XtPointer   call_data   : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void ServChainResCb( Widget w, XtPointer client_data, XtPointer call_data)
{
    	char             *selected_dev;
    	int              ind_serv = (int) client_data;
    	char             chainefile[1001];
    	char             *info_str, *reso_str, *strerr, s[1001];
    	XmTextPosition   cur_posit;
    	int              ind_ch, dev_found, free_place;
	long 		 num,i,l;
	DevLong		 error;
	char		 **res_array;

    	selected_dev = NULL;

    	selected_dev = XmTextGetSelection (serv_tab[ind_serv]->resotext);

    	if (selected_dev != NULL)
    	{
	
		xsSetCursor(serv_tab[ind_serv]->window,XC_watch);
		XFlush(XtDisplay(w));

		l = strlen(selected_dev);
		for (i = 0;i < l;i++)
			selected_dev[i] = tolower(selected_dev[i]);
			
/*** Check that the device has not been chained already ***/

       		ind_ch = 0;
       		dev_found = False;
       		while ( (ind_ch < CH_TAB_SIZE) && (dev_found == False) )
       		{
          		if ((serv_tab[ind_serv]->chaine_dev_arr)[ind_ch] != NULL)
			{
             			if ( strcasecmp ((serv_tab[ind_serv]->chaine_dev_arr)[ind_ch],
                             			  selected_dev) == 0 )
                			dev_found = True;
             			else
                			ind_ch++;
			}
          		else
             			ind_ch++;
       		}

       		if (dev_found == True)
       		{
          		sprintf(s,"The device %s has already been chained in this window.\n\n", selected_dev);
          		strcat(s, "If you want to repeat this operation, open another window\n");
          		strcat(s, "for ");
          		strcat(s, serv_tab[ind_serv]->servname);
          		strcat(s, " and then chaine ");
          		strcat(s, selected_dev);
          		strcat(s, " .\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(serv_tab[ind_serv]->window);
			XFlush(XtDisplay(w));
          		return;
       		}

/* Get device resource */

       		reso_str = NULL;
		if (db_deviceres(1,&selected_dev,&num,&res_array,&error))
		{
			strerr = dev_error_str(error);
			OpenMsgBox(widgtab[ErrorBoxID],strerr);
			free(strerr);
			XtFree(selected_dev);
			xsUnsetCursor(serv_tab[ind_serv]->window);
			XFlush(XtDisplay(w));
			return;
		}

/* Happy end : resu = NO_RESOURCE or NO_PROBLEM */
       
       		if (num == 0)
       		{
          		sprintf(s,"The device %s has no resources yet.\n", selected_dev);
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		if (reso_str != NULL)
				free(reso_str);
          		XtFree(selected_dev);
			xsUnsetCursor(serv_tab[ind_serv]->window);
			XFlush(XtDisplay(w));
          		return;
       		}
		
/* Build the string in Motif style */

		if (xsCreateStringForText(res_array,num,&reso_str))
		{
			for (i = 0;i < num;i++)
				free(res_array[i]);
			free(res_array);
          		sprintf(s,"Can't allocate memory\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(serv_tab[ind_serv]->window);
			XFlush(XtDisplay(w));
          		return;
       		}		

/*** Add the device into the array of the chained devices ***/

       		ind_ch = 0;
       		free_place = False;
       		while ( (ind_ch < CH_TAB_SIZE) && (free_place == False) )
       		{
          		if ((serv_tab[ind_serv]->chaine_dev_arr)[ind_ch] == NULL)
             			free_place = True;
          		else
             			ind_ch++;
       		}

       		if (free_place == True)
          		(serv_tab[ind_serv]->chaine_dev_arr)[ind_ch] = strdup(selected_dev);

/*** A comment to add to separate the chained device resources  ***/
/*** from the rest of the window contents.                      ***/

       		sprintf(s, "\n#\n####  Resources related to %s  ####\n#\n",selected_dev);
       		cur_posit = XmTextGetLastPosition (serv_tab[ind_serv]->resotext);
       		XmTextInsert(serv_tab[ind_serv]->resotext, cur_posit, s);

/**** Concatenate at the end of the file associated to the device ***/
/**** the chained resources retrieved.                            ***/
       
       		sprintf(chainefile, "/tmp/greta%d_ServChaine.res", pid);
       		devresfile_create(chainefile, reso_str);
		if (file_concat(chainefile,serv_tab[ind_serv]->file) == -1)
		{
			for (i = 0;i < num;i++)
				free(res_array[i]);
			free(res_array);
          		sprintf(s,"Can't open temporary file\n");
          		OpenMsgBox(widgtab[InfoBoxID], s);
          		XtFree(selected_dev);
			xsUnsetCursor(serv_tab[ind_serv]->window);
			XFlush(XtDisplay(w));
          		return;
		}
       		remove(chainefile);

/**** Add the new chained resources in the resource window     ****/
/**** associated with the device.                              ****/
       
       		cur_posit = XmTextGetLastPosition (serv_tab[ind_serv]->resotext);
       		XmTextInsert(serv_tab[ind_serv]->resotext, cur_posit, reso_str);

       		cur_posit = XmTextGetLastPosition (serv_tab[ind_serv]->resotext);
       		XmTextShowPosition(serv_tab[ind_serv]->resotext, cur_posit);

       		if (reso_str != NULL)
			free(reso_str);
		for (i = 0;i < num;i++)
			free(res_array[i]);
		free(res_array);
       		XtFree(selected_dev);
		
		xsUnsetCursor(serv_tab[ind_serv]->window);
		XFlush(XtDisplay(w));

    	}
}




/****************************************************************************
                                                                           
 Function     : void serv_reso_text_event_hand()

 Description  : the event handler attached to "resotext" Text Widget in
                the server Dialog windows. This handles the right button click
                to be a short cut to the ServChainResCb function.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : integer = index of the server window
                XEvent      *event      : the buttonPress event which triggered
                                          the event handler
                Boolean     *continue_to_dispatch : unused.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/


void serv_reso_text_event_hand( Widget w, XtPointer client_data,
                                          XEvent    *event,
                                          Boolean   *continue_to_dispatch)
{
    XButtonEvent     but_evt;
    char             *selected_dev;
    int              ind_dev = (int) client_data;

    selected_dev = NULL;

    if (event->type != ButtonPress)
       return;

    but_evt = event->xbutton;

    if (but_evt.button != Button3)
       return;

    ServChainResCb(w, client_data, NULL);
}









/****************************************************************************
                                                                           
 Function     : void LoadFileCb()

 Description  : callback attached to "Load" pushbuttons in the "Load : resource
                file" FileSelectionBox Dialog window. This function gets the
                pathname of the file to load and then calls changes the "title"
                of the window where the file is displayed accordingly.
                Afterwards it displays the whole file in that window.

 Arg(s) In    : Widget      w           : unused.
                XtPointer   client_data : unused.
                XtPointer   call_data   : used to get the name of the file.

 Arg(s) Out   : none

 Return(s)    : none
                                                                           
***************************************************************************/

void LoadFileCb( Widget w, XtPointer client_data, XtPointer call_data)
{

   XmFileSelectionBoxCallbackStruct    *file_sel_cbs;
   Boolean                             ret_val;
   char                                *fname_value=NULL;  
   int                                 file_loaded;

   file_sel_cbs = (XmFileSelectionBoxCallbackStruct *) call_data;

   XtVaSetValues(widgtab[FileLoadFormID],
                 XmNdialogTitle, file_sel_cbs->value, NULL);

   ret_val = XmStringGetLtoR(file_sel_cbs->value, XmFONTLIST_DEFAULT_TAG,
                                                  &fname_value);

   if (ret_val == True)
   {
      XmTextSetString(widgtab[FileLoadTextID], "File loaded!");

      file_loaded = -1;
      file_loaded = xsResfileLoad(fname_value, widgtab[FileLoadTextID]);

      if (file_loaded == 0)
         XtManageChild(widgtab[FileLoadFormID]);
	 
      XtFree(fname_value);
   }

}

void NewServOKCb(Widget w,XtPointer client_data,XtPointer call_data)
{
	char *ds_name;
	char *ds_pers_name;
	char *user_list;
	char *real_list;
	long nb_res,nb_dev;
	char **res_def,**dev_def;
	long l;
	long err_line,res,dev_err;
	DevLong error;
	long left,right;
	Time time;
	char mess[300];
   	XmAnyCallbackStruct *acs=(XmAnyCallbackStruct*)call_data;
	
/* Change cursor */

	xsSetCursor(XtParent(w), XC_watch);
	XFlush(XtDisplay(w));
	
/* Get DS name and check its length */

	ds_name = (char *)XmTextGetString(widgtab[ServNameTextID]);
	l = strlen(ds_name);
	if (l > DS_NAME_LENGTH)
	{
		XtFree(ds_name);
		OpenMsgBox(widgtab[ErrorBoxID],"Device server name too loong (Max = 23 chars.)");
		xsUnsetCursor(XtParent(w));
    		XFlush(XtDisplay(w));
		return;
	}
	if (l == 0)
	{
		XtFree(ds_name);
		OpenMsgBox(widgtab[ErrorBoxID],"No device server name defined !!");
		xsUnsetCursor(XtParent(w));
    		XFlush(XtDisplay(w));
		return;
	}
		
/* Get DS pers name and check its length */

	ds_pers_name = (char *)XmTextGetString(widgtab[PersNameTextID]);
	l = strlen(ds_pers_name);
	if (l > DSPERS_NAME_LENGTH)
	{
		XtFree(ds_name);
		XtFree(ds_pers_name);
		OpenMsgBox(widgtab[ErrorBoxID],"Device server personal name too loong (Max = 11 chars.)");
		xsUnsetCursor(XtParent(w));
    		XFlush(XtDisplay(w));
		return;
	}
	if (l == 0)
	{
		XtFree(ds_name);
		XtFree(ds_pers_name);
		OpenMsgBox(widgtab[ErrorBoxID],"No device server personal name defined !!");
		xsUnsetCursor(XtParent(w));
    		XFlush(XtDisplay(w));
		return;
	}
	
/* Compute real device list buffer length and allocate memory for it */

	user_list = (char *)XmTextGetString(widgtab[DevListTextID]);
	if (strlen(user_list) == 0)
	{
		XtFree(ds_name);
		XtFree(ds_pers_name);
		XtFree(user_list);
		OpenMsgBox(widgtab[ErrorBoxID],"No device defined for this server !!");
		xsUnsetCursor(XtParent(w));
    		XFlush(XtDisplay(w));
		return;
	}
	l = strlen(ds_name) + strlen(ds_pers_name) + 11 + strlen(user_list);
	if ((real_list = (char *)malloc(l + 1)) == NULL)
	{
		XtFree(ds_name);
		XtFree(ds_pers_name);
		XtFree(user_list);
		OpenMsgBox(widgtab[ErrorBoxID],"Can't allocate memory !!!");
		xsUnsetCursor(XtParent(w));
    		XFlush(XtDisplay(w));
		return;
	}
	
/* Build real device list */

	strcpy(real_list,ds_name);
	strcat(real_list,"/");
	strcat(real_list,ds_pers_name);
	strcat(real_list,"/device:");
	strcat(real_list,user_list);
	
/* Analyse real device list */

	res = db_analyze_data(Db_Buffer,real_list,&nb_dev,&dev_def,&nb_res,
			      &res_def,&err_line,&error);	

/* Display error message if the analysis fails */

	if (res == -1)
	{
		
		sprintf(mess,"Error at line %d\n",err_line);
		
/* Call _xc.s utility LineNbToLRPos */
	
		LineNbToLRPos(user_list,&err_line, &left, &right);
		
/* Call highlighting function */
	
		time = acs->event->xbutton.time;
		XmTextSetSelection(widgtab[DevListTextID],(XmTextPosition)left, (XmTextPosition)right,time);

		XtFree(ds_name);
		XtFree(ds_pers_name);
		XtFree(user_list);
		free(real_list);
		OpenMsgBox(widgtab[ErrorBoxID],mess);
		xsUnsetCursor(XtParent(w));
    		XFlush(XtDisplay(w));
		return;
	}
	
/* Update database with this new list */

	if (nb_dev != 0)
	{	
		res = db_upddev(nb_dev,dev_def,&dev_err,&error);
	
/* Display message if this call fails */

		if (res == -1)
		{
			FREE_STR_ARRAY(res_def,nb_res);
			FREE_STR_ARRAY(dev_def,nb_dev);
			strcpy(mess,"Can't update database\n");
			strcat(mess,"Not able to update device list\n");
			sprintf(&(mess[strlen(mess)]),"%s\n",dev_error_str(error));

			OpenMsgBox(widgtab[ErrorBoxID],mess);
			xsUnsetCursor(XtParent(w));
    			XFlush(XtDisplay(w));
			return;
		}
	}
	
/* Free memory */

	FREE_STR_ARRAY(res_def,nb_res);
	FREE_STR_ARRAY(dev_def,nb_dev);	
	XtFree(ds_name);
	XtFree(ds_pers_name);
	XtFree(user_list);
	free(real_list);
	
	XmTextSetString(widgtab[ServNameTextID],"");
	XmTextSetString(widgtab[PersNameTextID],"");
	XmTextSetString(widgtab[DevListTextID],"");
	xsUnsetCursor(XtParent(w));
    	XFlush(XtDisplay(w));
	XtUnmanageChild(XtParent(w));				
}

void NewServCancelCb(Widget w,XtPointer client_data,XtPointer call_data)
{
	XmTextSetString(widgtab[ServNameTextID],"");
	XmTextSetString(widgtab[PersNameTextID],"");
	XmTextSetString(widgtab[DevListTextID],"");
	
	XtUnmanageChild(XtParent(w));
}


void DevRestartCb(Widget w,XtPointer client_data,XtPointer call_data)
{
 	int ind=(int)client_data;
    
/* Position the sdd.h variable device_to_restart */

    	device_to_restart = ind;
	dev_dc_flag = GR_DEV;
}

void DevDcRestartCb(Widget w,XtPointer client_data,XtPointer call_data)
{
 	int ind=(int)client_data;
    
/* Position the sdd.h variable device_to_restart */

    	device_to_restart = ind;
	dev_dc_flag = GR_DEV_DC;
}

void ServRestartCb(Widget w,XtPointer client_data,XtPointer call_data)
{
	int ind = (int)client_data;
	
/* Position the sdd.h variable server_to_restart */

    	server_to_restart = ind;
	dev_dc_flag = GR_SERV;
}



void DevRestartSvcOK(Widget w,XtPointer client_data,XtPointer call_data)
{
	DevLong error;
	long restore;
	char *strerr;
	Widget w_curs;
	unsigned int pid;
	char host[40];
	char proc[40];
	char pers[40];
	char start_dev_name[40];
	devserver start;
	char full_strerr[512];
	char *ptr;
	unsigned long diff,pn;
	char tmp_host[40];
	char *inarg[5];
	char pid_str[10];
	DevVarStringArray in;
	long exported;
	CLIENT *cl;
	enum clnt_stat clnt_stat;
	char s[80];
	char *str;
	char theo_ds_name[80];
	
	if (dev_dc_flag == GR_DEV_DC)
		w_curs = dev_dc_tab[device_to_restart]->window;
	else if (dev_dc_flag == GR_DEV)
		w_curs = dev_tab[device_to_restart]->window;
	else
		w_curs = serv_tab[server_to_restart]->window;

    	xsSetCursor(XtParent(w_curs), XC_watch);
    	XFlush(XtDisplay(w));

/* Get mandatory parameters from global structures */

	if (dev_dc_flag == GR_DEV_DC)
	{
		pid = dev_dc_tab[device_to_restart]->pid;
		pn = dev_dc_tab[device_to_restart]->pn;
		strcpy(host,dev_dc_tab[device_to_restart]->host_name);
		strcpy(proc,dev_dc_tab[device_to_restart]->proc_name);
		strcpy(pers,dev_dc_tab[device_to_restart]->pers_name);
		exported = dev_dc_tab[device_to_restart]->exported;
	}
	else if (dev_dc_flag == GR_DEV)
	{
		pid = dev_tab[device_to_restart]->pid;
		pn = dev_tab[device_to_restart]->pn;
		strcpy(host,dev_tab[device_to_restart]->host_name);
		strcpy(proc,dev_tab[device_to_restart]->proc_name);
		strcpy(pers,dev_tab[device_to_restart]->pers_name);
		exported = dev_tab[device_to_restart]->exported;
	}
	else
	{
		pid = serv_tab[server_to_restart]->pid;
		pn = serv_tab[server_to_restart]->pn;
		strcpy(host,serv_tab[server_to_restart]->host_name);
		strcpy(proc,serv_tab[server_to_restart]->proc_name);
		strcpy(pers,serv_tab[server_to_restart]->pers_name);
		exported = serv_tab[server_to_restart]->restart;
	}	

/* Build starter device name */

	strcpy(start_dev_name,GR_START_DEV);
	ptr = strchr(host,'.');
	if (ptr == NULL)	
		strcat(start_dev_name,host);
	else
	{
		diff = (unsigned long)(ptr - host);
		strncpy(tmp_host,host,diff);
		tmp_host[diff] = '\0';
		strcat(start_dev_name,tmp_host);
	}
			
/* Import starter device */
		
	if (dev_import(start_dev_name,0,&start,&error))
	{
		sprintf(full_strerr,"Cant import starter device %s\n",start_dev_name);
		strerr = dev_error_str(error);
		strcat(full_strerr,strerr);
    		OpenMsgBox(widgtab[ErrorBoxID], full_strerr);
		free(strerr);
    		xsUnsetCursor(XtParent(w_curs));
    		XFlush(XtDisplay(w));
		return; 
	}

/* If for the database point of view, the server is running, test if it 
   effectively running with a call to the DS RPC_CHECK procedure.
   Restart a process only if this check is successfull. Otherwise only try
   to start the DS */
   
	if (exported == True)
	{
		cl = clnt_create(host,pn,4,"udp");

		if (cl == NULL)
		{
			restore = False;
		}
		else
		{

			str = s;
			clnt_stat = clnt_call(cl,RPC_CHECK,(xdrproc_t)xdr_void,NULL,(xdrproc_t)xdr_wrapstring,(caddr_t)&str,ds_tout);

			if (clnt_stat != RPC_SUCCESS)
			{
				restore = False;
			}
			else
			{
				strcpy(theo_ds_name,proc);
				strcat(theo_ds_name,"/");
				strcat(theo_ds_name,pers);
				
				if (strcmp(s,theo_ds_name) == 0)
					restore = True;
				else
					restore = False;
			}
			
			clnt_destroy(cl);
		}
		
/* Build command input argument for a restore command */

		if (restore == True)
		{
			sprintf(pid_str,"%d",pid);
	
			inarg[0] = pid_str;
			inarg[1] = proc;
			inarg[2] = pers;
			inarg[3] = "-m";
			inarg[4] = "#5";
	
			in.sequence = inarg;
			in.length = 5;

/* Restart the server. If the restart command fails with the error
   DevErr_NoProcessWithPid, only start the process */

			if (dev_putget(start,DevRestore,&in,D_VAR_STRINGARR,NULL,D_VOID_TYPE,&error))
			{
				if (error == DevErr_NoProcessWithPid)
				{
					inarg[0] = proc;
					inarg[1] = pers;
					inarg[2] = "-m";
					inarg[3] = "#5";
	
					in.sequence = inarg;
					in.length = 4;
				
					if (dev_putget(start,DevRun,&in,D_VAR_STRINGARR,NULL,D_VOID_TYPE,&error))
					{
						sprintf(full_strerr,"Error from starter device (%s) when trying to restart device server\n",start_dev_name);
						if (error == DevErr_CantFindExecutable)
							sprintf(&(full_strerr[strlen(full_strerr)]),"Cant find executable %s on host %s\n",proc,host);
						else
						{
							strerr = dev_error_str(error);
							strcat(full_strerr,strerr);
							free(strerr);
						}
    						OpenMsgBox(widgtab[ErrorBoxID], full_strerr);
						dev_free(start,&error);
    						xsUnsetCursor(XtParent(w_curs));
    						XFlush(XtDisplay(w));
						return;
					}
				}
				else
				{
					sprintf(full_strerr,"Error from starter device (%s) when trying to restart device server\n",start_dev_name);
					if (error == DevErr_CantKillProcess)
						sprintf(&(full_strerr[strlen(full_strerr)]),"Cant kill process %d on host %s\n",pid,host);
					else if (error == DevErr_CantFindExecutable)
						sprintf(&(full_strerr[strlen(full_strerr)]),"Cant find executable %s on host %s\n",proc,host);
					else
					{
						strerr = dev_error_str(error);
						strcat(full_strerr,strerr);
						free(strerr);
					}
    					OpenMsgBox(widgtab[ErrorBoxID], full_strerr);
					dev_free(start,&error);
    					xsUnsetCursor(XtParent(w_curs));
    					XFlush(XtDisplay(w));
					return;
				}
			}
		}
		else
		{
		
/* Send only a start command */

			inarg[0] = proc;
			inarg[1] = pers;
			inarg[2] = "-m";
			inarg[3] = "#5";
		
			in.sequence = inarg;
			in.length = 4;
		
/* Start the server */

			if (dev_putget(start,DevRun,&in,D_VAR_STRINGARR,NULL,D_VOID_TYPE,&error))
			{
				sprintf(full_strerr,"Error from starter device (%s) when trying to start device server\n",start_dev_name);
				if (error == DevErr_CantFindExecutable)
					sprintf(&(full_strerr[strlen(full_strerr)]),"Cant find executable %s on host %s\n",proc,host);
				else
				{
					strerr = dev_error_str(error);
					strcat(full_strerr,strerr);
					free(strerr);
				}
    				OpenMsgBox(widgtab[ErrorBoxID], full_strerr);
				dev_free(start,&error);
    				xsUnsetCursor(XtParent(w_curs));
    				XFlush(XtDisplay(w));
				return;
			}
		}
	}
	else
	{
	
/* Build command arguments but only for a start command */

		inarg[0] = proc;
		inarg[1] = pers;
		inarg[2] = "-m";
		inarg[3] = "#5";
		
		in.sequence = inarg;
		in.length = 4;
		
/* Start the server */

		if (dev_putget(start,DevRun,&in,D_VAR_STRINGARR,NULL,D_VOID_TYPE,&error))
		{
			sprintf(full_strerr,"Error from starter device (%s) when trying to start device server\n",start_dev_name);
			if (error == DevErr_CantFindExecutable)
				sprintf(&(full_strerr[strlen(full_strerr)]),"Cant find executable %s on host %s\n",proc,host);
			else
			{
				strerr = dev_error_str(error);
				strcat(full_strerr,strerr);
				free(strerr);
			}
    			OpenMsgBox(widgtab[ErrorBoxID], full_strerr);
			dev_free(start,&error);
    			xsUnsetCursor(XtParent(w_curs));
    			XFlush(XtDisplay(w));
			return;
		}
	}

/* Free starter device and change cursor back */

	dev_free(start,&error);
	
    	xsUnsetCursor(XtParent(w_curs));
    	XFlush(XtDisplay(w));	
}

