#include <cdevSystem.h>
#include <cdevRequestObject.h>
#include <cdevData.h>
#include <cdevDirectory.h>
#include "DumpAllHandler.h"
#include "cdevGenericServerTags.h"

FifoQueue results        [MAX_SERVERS];
int       completionCodes[MAX_SERVERS];

static char * NameServerDefinitionString =
"service rns { tags {PV} }\n\
class RNS { messages { query rns; get rns; monitorOn rns; monitorOff rns; } }\n\
RNS :\nNameServer\n;\n";

cdevReactor DumpAllReactor;

void ReportStandard ( char * Domain, char * Name, char * Server, int Port, int index );
void ReportBrief    ( int index );
void ReportServerBrief ( cdevData & data );
void ReportClientBrief ( cdevData & data );
void ReportComplete ( int index );
void ReportServerComplete ( cdevData & data );
void ReportClientComplete ( cdevData & data );
void *getItem ( cdevData & data,  char * tag, unsigned defaultItem);
void *getItem ( cdevData & data,  char * tag, float defaultItem);
void *findItem ( cdevData & data, char * tag, cdevDataTypes type, size_t maxItems, void *defaultItem);


int main (int argc, char ** argv)
	{
	char * cdevNameServer = getenv("CDEV_NAME_SERVER");
	cdevGenericServerTagDef tags;

	typedef enum { STANDARD=0, BRIEF=1, COMPLETE=2, SIMPLE=4, BOGUS=8} ReportType;
	ReportType reportType = STANDARD;
	
	if(cdevNameServer==NULL)
		{
		fprintf(stdout, "-----------------------------------------------------------------------\n");
		fprintf(stdout, "ERROR : CDEV_NAME_SERVER is not defined in the local environment.\n");
		fprintf(stdout, "        Set the CDEV_NAME_SERVER variable to indicate the host where \n");
		fprintf(stdout, "        the name server is running prior to executing this application.\n");
		fprintf(stdout, "-----------------------------------------------------------------------\n");
		fflush(stdout);
		exit(1);
		}
	
	for(int x=1; x<argc; x++)
		{
		if(!strcmp(argv[x], "-a")) 
			{
			if(reportType==STANDARD || reportType==COMPLETE) reportType = COMPLETE;
			else	{
				fprintf(stderr, "ERROR: Only one of option -a, -b, or -s can be used\n");
				fflush(stderr);
				reportType = BOGUS;
				}
			}
		else if(!strcmp(argv[x], "-b"))
			{
			if(reportType==STANDARD || reportType==BRIEF) reportType = BRIEF;
			else	{
				fprintf(stderr, "ERROR: Only one of option -a, -b, or -s can be used\n");
				fflush(stderr);
				reportType = BOGUS;
				}
			}
		else if(!strcmp(argv[x], "-s"))
			{
			if(reportType==STANDARD || reportType==SIMPLE) reportType = SIMPLE;
			else	{
				fprintf(stderr, "ERROR: Only one of option -a, -b, or -s can be used\n");
				fflush(stderr);
				reportType = BOGUS;
				}			
			}
		else	{
			fprintf(stderr, "ERROR: Unknown argument %s passed to %s\n", argv[x], argv[0]);
			fflush(stderr);
			reportType = BOGUS;
			}
		
		if(reportType==BOGUS)
			{
			fprintf(stderr, "Format is : %s (-a OR -b OR -s)\n", argv[0]);
			fprintf(stderr, "            -a : print a complete report\n");
			fprintf(stderr, "            -b : print a brief report\n");
			fprintf(stderr, "            -s : print a simple report\n");
			fprintf(stderr, "\n            If neither option is specified\n");
			fprintf(stderr, "            then a standard report will be\n");
			fprintf(stderr, "            produced.\n");
			fflush(stderr);
			exit(1); 
			}
		}
	 
		
	// *********************************************************************
	// * Determine if the NameServer has been provided in the CDEVDDL file.
	// * If not, add the NameServer to the cdevDirectory.
	// *********************************************************************
	cdevDirectory & nameServer = cdevSystem::defaultSystem().nameServer();
	cdevData        request;
	cdevData        reply;
	
	memset(completionCodes, 0, sizeof(completionCodes));
	
	request.insert("device", "NameServer");
	if(nameServer.send("queryClass", request, reply)==CDEV_NOTFOUND)
		{
		request.insert("file", NameServerDefinitionString);
		nameServer.send("update", request, NULL);
		}

	cdevData in, data;
	cdevRequestObject * NameServerQuery = cdevRequestObject::attachPtr("NameServer", "query");
	in.insert("queryMsg", "all");
	if(NameServerQuery==NULL || NameServerQuery->send(in, data)!=CDEV_SUCCESS)
		{
		cdevSystem::defaultSystem().reportError(CDEV_SEVERITY_ERROR, "DumpServer", NULL,  "Failed to communicate with Name Server");
		return 0;
		}

	size_t cnt = 0, cnt1 = 0;
	char ** domainPtr = NULL;
	char ** serverPtr = NULL;
	char ** hostPtr   = NULL;
	int   * portPtr   = NULL;
	int   * status    = NULL;
		
	if(data.getElems("domain", &cnt1)==CDEV_SUCCESS && cnt1>cnt) cnt = cnt1;
	if(data.getElems("name", &cnt1)==CDEV_SUCCESS   && cnt1>cnt) cnt = cnt1;
	if(data.getElems("host", &cnt1)==CDEV_SUCCESS   && cnt1>cnt) cnt = cnt1;
	if(data.getElems("port", &cnt1)==CDEV_SUCCESS   && cnt1>cnt) cnt = cnt1;
	if(data.getElems("status", &cnt1)==CDEV_SUCCESS && cnt1>cnt) cnt = cnt1;
	
	if(cnt>0)
		{
		domainPtr = new char *[cnt];
		serverPtr = new char *[cnt];
		hostPtr   = new char *[cnt];
		portPtr   = new int   [cnt];
		status    = new int   [cnt];
		
		memset(domainPtr, 0, sizeof(char *)*cnt);
		memset(serverPtr, 0, sizeof(char *)*cnt);
		memset(hostPtr, 0, sizeof(char *)*cnt);
		memset(portPtr, 0, sizeof(int)*cnt);
		memset(status, 0, sizeof(int)*cnt);
		
		data.get("domain", domainPtr);
		data.get("name", serverPtr);
		data.get("host", hostPtr);
		data.get("port", portPtr);
		data.get("status", status);

		int i, retry=0;
		if(reportType==SIMPLE)
			{
			fprintf(stdout, "\n================================================================================\n");
			fprintf(stdout, " THIS DATA OBTAINED FROM CDEV NAME SERVER AT : %s\n", cdevNameServer);
			fprintf(stdout, "================================================================================\n\n");
		
			fprintf(stdout, "\n-------------------------------------------------------------------------------\n");
			fprintf(stdout, " DOMAIN                  NAME                    HOST                     PORT  \n");
			fprintf(stdout, "--------------------------------------------------------------------------------\n");
			fflush(stdout);
			
			for(i=0; i<cnt; i++)
				{
				if(status[i]==0)
					{
					fprintf(stdout, " %-24s%-24s%-24s% 5i\n", domainPtr[i], serverPtr[i], hostPtr[i], portPtr[i]);
					fflush(stdout);
					}
				}
			}
		else	{
			DumpAllHandler ** handlers = new DumpAllHandler *[cnt];
			for(i=0; i<cnt && i<MAX_SERVERS; i++)
				{
				if(status[i]==0) handlers[i]=new DumpAllHandler(hostPtr[i], portPtr[i], DumpAllReactor, i);
				else completionCodes[i] = -1;
				}
			DumpAllReactor.handleEvents(0.01);
	
			for(i=0; i<cnt && retry<100; )
				{
				if(completionCodes[i]==0)
					{
					DumpAllReactor.handleEvents(0.01);
					retry++;
					}
				else i++;
				}
					
			fprintf(stdout, "\n================================================================================\n");
			fprintf(stdout, " THIS DATA OBTAINED FROM CDEV NAME SERVER AT : %s\n", cdevNameServer);
			fprintf(stdout, "================================================================================\n\n");
			fflush(stdout);
			
			for(i=0; i<cnt; i++)
				{
				if(completionCodes[i]!=1)
					{
					fprintf(stdout, "\nERROR : Can't talk to %s in domain %s on %s:%i\n", serverPtr[i], domainPtr[i], hostPtr[i], portPtr[i]);
					fflush(stdout);
					completionCodes[i] = -1;
					}
				}

			for(i=0; i<cnt; i++)
				{
				if(completionCodes[i]==1)
					{
					if(reportType==STANDARD) ReportStandard(domainPtr[i], serverPtr[i], hostPtr[i], portPtr[i], i);
					else if(reportType==BRIEF) ReportBrief(i);
					else if(reportType==COMPLETE) ReportComplete(i);
					}
				}
			}
		}
	else	{
		fprintf(stdout, "-----------------------------------------------------------------------\n");
		fprintf(stdout, " No CDEV Servers are currently registered with the CDEV Name Server\n");
		fprintf(stdout, " running on %s\n", cdevNameServer);
		fprintf(stdout, "-----------------------------------------------------------------------\n");
		fflush(stdout);
		}
	fprintf(stdout, "\n\n");
	fflush(stdout);
	return 0;
	}


void ReportStandard ( char * Domain, char * Name, char * Server, int Port, int index )
	{
	static int headerDefined = 0;
	
	cdevMessage *ServerInfo=NULL, *ClientInfo=NULL, *temp;
	while(completionCodes[index]==1 && (temp = (cdevMessage *)results[index].dequeue())!=NULL)
		{
		if(temp->getTransIndex()==1)
			{
			if(ServerInfo!=NULL) delete ServerInfo;
			ServerInfo = temp;
			}
		else if(temp->getTransIndex()==2)
			{
			if(ClientInfo!=NULL) delete ClientInfo;
			ClientInfo = temp;
			}
		}
	char   domain[255];
	char   name  [255];
	char   server[255];
	char   startTimeStr[255];
	int    port        = 0;
	float  utilization = 0;
	time_t startTime   = 0;
	int    clientCnt   = 0;
	
	if(ServerInfo)
		{
		cdevData * data = ServerInfo->getData();
		if(data->get("domain", domain, 255)!=CDEV_SUCCESS) strcpy(domain, Domain);
		if(data->get("server", name, 255)!=CDEV_SUCCESS)   strcpy(name, Name);
		if(data->get("host", server, 255)!=CDEV_SUCCESS)   strcpy(server, Server);
		if(data->get("port", &port)!=CDEV_SUCCESS)         port = Port;
		if(data->get("pctcpu", &utilization)!=CDEV_SUCCESS) utilization = 0;
		if(data->get("starttime", &startTime)!=CDEV_SUCCESS) startTime = time(NULL);
		}
	else 	{
		strcpy(domain, Domain);
		strcpy(name, Name);
		strcpy(server, Server);
		port        = Port;
		utilization = 0;
		startTime   = time(NULL);
		}
	
	sprintf(startTimeStr, "%s", startTime?ctime(&startTime):"UNKNOWN");
	if(strchr(startTimeStr, '\n')!=NULL) *(strchr(startTimeStr, '\n'))=0;
	
	if(!headerDefined)
		{
		fprintf(stdout, "\n--------------------------------------------------------------------------------\n");
		fprintf(stdout, " DOMAIN           NAME             HOST              PORT   CPU%%  START\n");
		fprintf(stdout, "--------------------------------------------------------------------------------\n");
		fflush(stdout);
		headerDefined = 1;
		}
	fprintf(stdout, " %-17s%-17s%-17s% 5i  %5.2f  %s\n", domain, name, server, port, utilization*100.0, startTimeStr);
	fflush(stdout);
	if(ServerInfo) delete ServerInfo;
	if(ClientInfo) delete ClientInfo;
	}

void ReportBrief    ( int index )
	{
	static int headerDefined = 0;
	cdevMessage *ServerInfo=NULL, *ClientInfo=NULL, * temp;
	while(completionCodes[index]==1 && (temp = (cdevMessage *)results[index].dequeue())!=NULL)
		{
		if(temp->getTransIndex()==1)
			{
			if(ServerInfo!=NULL) delete ServerInfo;
			ServerInfo = temp;
			}
		else if(temp->getTransIndex()==2)
			{
			if(ClientInfo!=NULL) delete ClientInfo;
			ClientInfo = temp;
			}
		}

		
	cdevData * data;
	if(ServerInfo && (data=ServerInfo->getData())!=NULL)
		{
		if(!headerDefined)
			{
			fprintf(stdout, "\n--------------------------------------------------------------------------------");
			headerDefined = 1;
			}
		fprintf(stdout, "\n DOMAIN           NAME             HOST              PORT   CPU%%  START\n");
		fprintf(stdout, "--------------------------------------------------------------------------------\n");
		fflush(stdout);
		
		ReportServerBrief(*data);
		delete ServerInfo;
		}
	else return;
	
	if(ClientInfo && (data=ClientInfo->getData())!=NULL)
		{
		ReportClientBrief(*data);
		delete ClientInfo;
		}
	}	

void ReportServerBrief ( cdevData & data )
	{
	char    *unknown     = "UNKNOWN";
	char    *domain      = (char *)findItem(data, "domain", CDEV_STRING, 1, unknown);;
	char    *server      = (char *)findItem(data, "server", CDEV_STRING, 1, unknown);;
	char    *host        = (char *)findItem(data, "host", CDEV_STRING, 1, unknown);;
	int      port        = *(unsigned *)getItem(data, "port", 0U);
	time_t   starttime   = *(unsigned *)getItem(data, "starttime", (unsigned)time(NULL));
	float    pctcpu      = *(float *)getItem(data, "pctcpu", (float)0.0);
	char     startTimeStr[255];

	sprintf(startTimeStr, "%s", starttime?ctime(&starttime):"UNKNOWN");
	if(strchr(startTimeStr, '\n')!=NULL) *(strchr(startTimeStr, '\n'))=0;

	fprintf(stdout, " %-17s%-17s%-17s% 5i  %5.2f  %s\n", domain, server, host, port, pctcpu*100.0, startTimeStr);
	fflush(stdout);
	return;
	}


void ReportClientBrief ( cdevData & data )
	{
	static char * ClientInfoTags[]=
		{
		"username", "group", "uid", "gid", "pid", "program",
		"commandline", "starttime", "connecttime", "host",
		"os", "osversion", "osrelease", "machine", "shell",
		"socket", "sendPktCnt", "recvPktCnt", "\0",
		};
	size_t i, j;
	size_t nClients = 0;
	
	data.getElems(ClientInfoTags[0], &nClients);
	
	for(i=0; *ClientInfoTags[i]!=0; i++)
		{
		data.getElems(ClientInfoTags[i], &j);
		if(j!=nClients)
			{
			fprintf(stdout, "ERROR : Inconsistent data in ClientInfo Structure\n");
			fflush(stdout);
			return;
			}
		}
	
	if(nClients==0) return;
	
	unsigned * connecttime = (unsigned *)findItem(data, "connecttime", CDEV_UINT32, nClients, NULL);
	
	char    ** username       = NULL;
	char     * usernamePtr    = NULL;
	char    ** program        = NULL;
	char     * programPtr     = NULL;
	char    ** host           = NULL;
	char     * hostPtr        = NULL;
	
	if(nClients>1)
		{
		username    = (char **)   findItem(data, "username", CDEV_STRING, nClients, NULL);
		program     = (char **)   findItem(data, "program", CDEV_STRING, nClients, NULL);
		host        = (char **)   findItem(data, "host", CDEV_STRING, nClients, NULL);
		}
	else	{
		username    = &(usernamePtr    = (char *)findItem(data, "username", CDEV_STRING, nClients, NULL));
		program     = &(programPtr     = (char *)findItem(data, "program", CDEV_STRING, nClients, NULL));
		host        = &(hostPtr        = (char *)findItem(data, "host", CDEV_STRING, nClients, NULL));
		}
		
	if(username==NULL || program==NULL || connecttime==NULL || host==NULL)
	   	{
	   	fprintf(stdout, "ERROR : Inconsistent data in ClientInfo Structure\n");
	   	fflush(stdout);
		return;
	   	}
	   	
	for(i=0; i<nClients; i++)
		{
		char connectTimeStr[255];

		if(connecttime[i]==0) connecttime[i] = (unsigned)time(NULL);
		sprintf(connectTimeStr, "%s", connecttime[i]?ctime((time_t *)&connecttime[i]):"UNKNOWN");
		if(strchr(connectTimeStr, '\n')!=NULL) *(strchr(connectTimeStr, '\n'))=0;

		fprintf(stdout, "\n                  %s (%s on %s) connected at %s", program[i], username[i], host[i], connectTimeStr);
		}
	fprintf(stdout, "\n\n");
	fflush(stdout);
	return;	
	}

void ReportComplete ( int index )
	{
	cdevMessage *ServerInfo=NULL, *ClientInfo=NULL, * temp;
	while(completionCodes[index]==1 && (temp = (cdevMessage *)results[index].dequeue())!=NULL)
		{
		if(temp->getTransIndex()==1)
			{
			if(ServerInfo!=NULL) delete ServerInfo;
			ServerInfo = temp;
			}
		else if(temp->getTransIndex()==2)
			{
			if(ClientInfo!=NULL) delete ClientInfo;
			ClientInfo = temp;
			}
		}

	cdevData * data;
	if(ServerInfo && (data=ServerInfo->getData())!=NULL)
		{
		ReportServerComplete(*data);
		delete ServerInfo;
		}
	else return;

	if(ClientInfo && (data=ClientInfo->getData())!=NULL)
		{
		ReportClientComplete(*data);
		delete ClientInfo;
		}
	}


void ReportServerComplete ( cdevData & data )
	{
	char    *unknown     = "UNKNOWN";
	char    *username    = (char *)findItem(data, "username", CDEV_STRING, 1, unknown);
	char    *group       = (char *)findItem(data, "group", CDEV_STRING, 1, unknown);;
	unsigned pid         = *(unsigned *)getItem(data, "pid", 0U);
	unsigned uid         = *(unsigned *)getItem(data, "uid", 0U);
	unsigned gid         = *(unsigned *)getItem(data, "gid", 0U);
	char    *domain      = (char *)findItem(data, "domain", CDEV_STRING, 1, unknown);;
	char    *server      = (char *)findItem(data, "server", CDEV_STRING, 1, unknown);;
	char    *host        = (char *)findItem(data, "host", CDEV_STRING, 1, unknown);;
	int      port        = *(unsigned *)getItem(data, "port", 0U);
	char    *os          = (char *)findItem(data, "os", CDEV_STRING, 1, unknown);;
	char    *osrelease   = (char *)findItem(data, "osrelease", CDEV_STRING, 1, unknown);;
	char    *osversion   = (char *)findItem(data, "osversion", CDEV_STRING, 1, unknown);;
	char    *machine     = (char *)findItem(data, "machine", CDEV_STRING, 1, unknown);;
	char    *shell       = (char *)findItem(data, "shell", CDEV_STRING, 1, unknown);;
	char    *program     = (char *)findItem(data, "program", CDEV_STRING, 1, unknown);;
	char    *commandline = (char *)findItem(data, "commandline", CDEV_STRING, 1, unknown);;
	time_t   starttime   = *(unsigned *)getItem(data, "starttime", (unsigned)time(NULL));
	float    pctcpu      = *(float *)getItem(data, "pctcpu", (float)0.0);
	unsigned datasize    = *(unsigned *)getItem(data, "datasize", 0U);
	unsigned sendPktCnt  = *(unsigned *)getItem(data, "sendPktCnt", 0U);
	unsigned recvPktCnt  = *(unsigned *)getItem(data, "recvPktCnt", 0U);
	char     startTimeStr[255];
	char     userStr[255];
	char     groupStr[255];
	char     osStr[255];
	
	sprintf (startTimeStr, "%s", starttime?ctime(&starttime):"UNKNOWN");
	if(strchr(startTimeStr, '\n')!=NULL) *(strchr(startTimeStr, '\n'))=0;
	sprintf (userStr, "%s (%i)", username, uid);
	sprintf (groupStr, "%s (%i)", group, gid);
	
	if(!strcmp(os, "UNKNOWN")) strcpy(osStr, os);
	else sprintf (osStr, "%s %s %s %s", os, machine, osrelease, osversion);
	
	fprintf(stdout, "-------------------------------------------------------------------------------\n");
	fprintf(stdout, "DOMAIN  : %-35s SERVER  : %-35s\n", domain, server);
	fprintf(stdout, "HOST    : %-35s PORT    : %i\n", host, port);
	fprintf(stdout, "OWNER   : %-35s GROUP   : %-35s\n", userStr, groupStr);
	fprintf(stdout, "OS      : %-35s START   : %-35s\n", osStr, startTimeStr);
	fprintf(stdout, "SHELL   : %-35s PROGRAM : %s (%i)\n", shell, program, pid);
	fprintf(stdout, "%% CPU   : %-35.2f SIZE    : %i\n", pctcpu*100.0, datasize);
	fprintf(stdout, "PKT SENT: %-35i PKT RECV: %-35i\n", sendPktCnt, recvPktCnt);  
	fprintf(stdout, "COMMAND : %s\n", commandline);
	fflush(stdout);
	};
	


void ReportClientComplete ( cdevData & data )
	{
	static char * ClientInfoTags[]=
		{
		"username", "group", "uid", "gid", "pid", "program",
		"commandline", "starttime", "connecttime", "host",
		"os", "osversion", "osrelease", "machine", "shell",
		"socket", "sendPktCnt", "recvPktCnt", "\0",
		};
	size_t i, j;
	size_t nClients = 0;
	
	data.getElems(ClientInfoTags[0], &nClients);
	
	for(i=0; *ClientInfoTags[i]!=0; i++)
		{
		data.getElems(ClientInfoTags[i], &j);
		if(j!=nClients)
			{
			fprintf(stdout, "ERROR : Inconsistent data in ClientInfo Structure\n");
			fflush(stdout);
			return;
			}
		}
	
	if(nClients==0) return;
	
	unsigned * uid         = (unsigned *)findItem(data, "uid", CDEV_UINT32, nClients, NULL);
	unsigned * gid         = (unsigned *)findItem(data, "gid", CDEV_UINT32, nClients, NULL);
	unsigned * pid         = (unsigned *)findItem(data, "pid", CDEV_UINT32, nClients, NULL);
	unsigned * starttime   = (unsigned *)findItem(data, "starttime", CDEV_UINT32, nClients, NULL);
	unsigned * connecttime = (unsigned *)findItem(data, "connecttime", CDEV_UINT32, nClients, NULL);
	unsigned * socket      = (unsigned *)findItem(data, "socket", CDEV_UINT32, nClients, NULL);
	unsigned * sendPktCnt  = (unsigned *)findItem(data, "sendPktCnt", CDEV_UINT32, nClients, NULL);
	unsigned * recvPktCnt  = (unsigned *)findItem(data, "recvPktCnt", CDEV_UINT32, nClients, NULL);
	
	char    ** username       = NULL;
	char     * usernamePtr    = NULL;
	char    ** group          = NULL;
	char     * groupPtr       = NULL;
	char    ** program        = NULL;
	char     * programPtr     = NULL;
	char    ** commandline    = NULL;
	char     * commandlinePtr = NULL;
	char    ** host           = NULL;
	char     * hostPtr        = NULL;
	char    ** os             = NULL;
	char     * osPtr          = NULL;
	char    ** osversion      = NULL;
	char     * osversionPtr   = NULL;
	char    ** osrelease      = NULL;
	char     * osreleasePtr   = NULL;
	char    ** machine        = NULL;
	char     * machinePtr     = NULL;
	char    ** shell          = NULL;
	char     * shellPtr       = NULL;
	
	if(nClients>1)
		{
		username    = (char **)   findItem(data, "username", CDEV_STRING, nClients, NULL);
		group       = (char **)   findItem(data, "group", CDEV_STRING, nClients, NULL);
		program     = (char **)   findItem(data, "program", CDEV_STRING, nClients, NULL);
		commandline = (char **)   findItem(data, "commandline", CDEV_STRING, nClients, NULL);
		host        = (char **)   findItem(data, "host", CDEV_STRING, nClients, NULL);
		os          = (char **)   findItem(data, "os", CDEV_STRING, nClients, NULL);
		osversion   = (char **)   findItem(data, "osversion", CDEV_STRING, nClients, NULL);
		osrelease   = (char **)   findItem(data, "osrelease", CDEV_STRING, nClients, NULL);
		machine     = (char **)   findItem(data, "machine", CDEV_STRING, nClients, NULL);
		shell       = (char **)   findItem(data, "shell", CDEV_STRING, nClients, NULL);
		}
	else	{
		username    = &(usernamePtr    = (char *)findItem(data, "username", CDEV_STRING, nClients, NULL));
		group       = &(groupPtr       = (char *)findItem(data, "group", CDEV_STRING, nClients, NULL));
		program     = &(programPtr     = (char *)findItem(data, "program", CDEV_STRING, nClients, NULL));
		commandline = &(commandlinePtr = (char *)findItem(data, "commandline", CDEV_STRING, nClients, NULL));
		host        = &(hostPtr        = (char *)findItem(data, "host", CDEV_STRING, nClients, NULL));
		os          = &(osPtr          = (char *)findItem(data, "os", CDEV_STRING, nClients, NULL));
		osversion   = &(osversionPtr   = (char *)findItem(data, "osversion", CDEV_STRING, nClients, NULL));
		osrelease   = &(osreleasePtr   = (char *)findItem(data, "osrelease", CDEV_STRING, nClients, NULL));
		machine     = &(machinePtr     = (char *)findItem(data, "machine", CDEV_STRING, nClients, NULL));
		shell       = &(shellPtr       = (char *)findItem(data, "shell", CDEV_STRING, nClients, NULL));
		}
		
	if(username==NULL || group==NULL || uid==NULL || gid==NULL || pid==NULL || program==NULL ||
	   commandline==NULL || starttime==NULL || connecttime==NULL || host==NULL || os==NULL ||
	   osversion==NULL || osrelease==NULL || machine==NULL || shell==NULL || socket==NULL ||
	   sendPktCnt==NULL || recvPktCnt==NULL)
	   	{
	   	fprintf(stdout, "ERROR : Inconsistent data in ClientInfo Structure\n");
	   	fflush(stdout);
		return;
	   	}
	   	
	fprintf(stdout, "CLIENTS : %i Clients Attached\n", nClients);
	
	for(i=0; i<nClients; i++)
		{
		char startTimeStr[255];
		char connectTimeStr[255];
		char architecture[255];
		
		if(starttime[i]==0)   starttime[i] = (unsigned)time(NULL);
		if(connecttime[i]==0) connecttime[i] = (unsigned)time(NULL);
		if(!strcmp(os[i], "UNKNOWN")) strcpy(architecture, "UNKNOWN");
		else sprintf(architecture, "%s %s %s %s", os[i], machine[i], osversion[i], osrelease[i]);
		
		sprintf(startTimeStr,   "%s",  starttime[i]?ctime((time_t *)&starttime[i]):"UNKNOWN");
		sprintf(connectTimeStr, "%s",  connecttime[i]?ctime((time_t *)&connecttime[i]):"UNKNOWN");
		if(strchr(startTimeStr, '\n')!=NULL) *(strchr(startTimeStr, '\n'))=0;
		if(strchr(connectTimeStr, '\n')!=NULL) *(strchr(connectTimeStr, '\n'))=0;

		fprintf(stdout, "          ---------------------------------------------------------------------\n");
		fprintf(stdout, "          OWNER        : %s (%i)\n", username[i], uid[i]);
		fprintf(stdout, "          GROUP        : %s (%i)\n", group[i], gid[i]);
		fprintf(stdout, "          PROGRAM      : %s (%i)\n", program[i], pid[i]);
		fprintf(stdout, "          COMMAND      : %s\n",      commandline[i]);
		fprintf(stdout, "          START TIME   : %s\n", startTimeStr);
		fprintf(stdout, "          CONNECT TIME : %s\n", connectTimeStr);
		fprintf(stdout, "          HOST         : %s\n",      host[i]);
		fprintf(stdout, "          ARCHITECTURE : %s\n", architecture);
		fprintf(stdout, "          SHELL        : %s\n", shell[i]);
		fprintf(stdout, "          PACKETS SENT : %i\n", sendPktCnt[i]);
		fprintf(stdout, "          PACKETS READ : %i\n", recvPktCnt[i]);
		fflush(stdout);
		}
	return;	
	}
	
	
void *getItem ( cdevData & data,  char * tag, unsigned defaultItem)
	{
	int      actualTag   = 0;
	size_t   actualItems = 0;
	static   unsigned result;

	result = defaultItem;	
	
	cdevData::tagC2I(tag, &actualTag);
	if(actualTag!=0)
		{
		data.getElems(actualTag, &actualItems);
		}
	if(actualTag!=0 && actualItems==1)
		{
		data.get(actualTag, &result);
		}
	return (void *)&result;
	}
	
void *getItem ( cdevData & data,  char * tag, float defaultItem)
	{
	int      actualTag   = 0;
	size_t   actualItems = 0;
	static float result;
	
	result = defaultItem;	
	
	cdevData::tagC2I(tag, &actualTag);
	if(actualTag!=0)
		{
		data.getElems(actualTag, &actualItems);
		}
	if(actualTag!=0 && actualItems==1)
		{
		data.get(actualTag, &result);
		}
	return (void *)&result;
	}
	
void *findItem ( cdevData & data, char * tag, cdevDataTypes type, size_t maxItems, void * defaultItem)
	{
	int           actualTag       = 0;
	cdevDataTypes actualDataType  = CDEV_INVALID;
	size_t        actualItems     = 0;
	void *        item            = defaultItem;
	
	cdevData::tagC2I(tag, &actualTag);
	if(actualTag!=0)
		{
		data.getElems(actualTag, &actualItems);
		actualDataType = data.getType(actualTag);
		}
	
	if(actualTag!=0 && actualDataType==type && actualItems>0 && actualItems<=maxItems)
		{
		data.find(actualTag, item);
		}
	return item;
	}
