#include <cdevPlatforms.h>
#include <cdevData.h>
#include <time.h>

class ClientInfoStruct
{
private:
	char   unknown[8];
	char * username;
	char * group;
	unsigned uid;
	unsigned gid;
	unsigned pid;
	char * program;
	char * commandline;
	time_t starttime;
	time_t connecttime;
	char * host;
	char * os;
	char * osrelease;
	char * osversion;
	char * machine;
	char * shell;
	
private:
	void updateDataString ( cdevData & data, char * tag, char * &item )
		{
		size_t nelems = 0;

		if(data.getElems(tag, &nelems)==CDEV_SUCCESS &&
		   nelems==1 && data.getType(tag)==CDEV_STRING)
		   	{
		   	if(item!=NULL) delete item;
		   	item = NULL;
		   	data.get(tag, &item);
		   	}
		}
	
	void updateDataInt ( cdevData & data, char * tag, unsigned &item )
		{
		size_t nelems = 0;
		if(data.getElems(tag, &nelems)==CDEV_SUCCESS && nelems==1)
			{
			data.get(tag, &item);
			}
		}

public:
	ClientInfoStruct ( void )
		: username(NULL), group(NULL), uid(0), gid(0), pid(0),
		 program(NULL), commandline(NULL), starttime(0), 
		 connecttime(0), host(NULL), os(NULL), osrelease(NULL),
		 osversion(NULL), machine(NULL), shell(NULL)
		 {
		 strcpy(unknown, "UNKNOWN");
		 }
	
	~ClientInfoStruct ( void )
		{
		if(username) delete username;
		if(group)    delete group;
		if(program)  delete program;
		if(commandline) delete commandline;
		if(host)        delete host;
		if(os)          delete os;
		if(osrelease)   delete osrelease;
		if(osversion)   delete osversion;
		if(machine)     delete machine;
		if(shell)       delete shell;
		}
	
	void updateClientInfo ( cdevData & data )
		{
		updateDataString(data, "username", username);
		updateDataString(data, "group", group);
		updateDataInt   (data, "uid", uid);
		updateDataInt   (data, "gid", gid);
		updateDataInt   (data, "pid", pid);
		updateDataString(data, "program", program);
		updateDataString(data, "commandline", commandline);
		updateDataInt   (data, "starttime", (unsigned &)starttime);
		updateDataInt   (data, "connecttime", (unsigned &)connecttime);
		updateDataString(data, "host", host);
		updateDataString(data, "os", os);
		updateDataString(data, "osrelease", osrelease);
		updateDataString(data, "osversion", osversion);
		updateDataString(data, "machine", machine);
		updateDataString(data, "shell", shell);
		connecttime = time(NULL);
		}

	char *   getUsername      ( void ) { return username?username:unknown; }
	char *   getGroup         ( void ) { return group?group:unknown; }
	unsigned getUid           ( void ) { return uid; }
	unsigned getGid           ( void ) { return gid; }
	unsigned getPid           ( void ) { return pid; }
	char *   getProgram       ( void ) { return program?program:unknown; }
	char *   getCommandLine   ( void ) { return commandline?commandline:unknown; }
	time_t   getStartTime     ( void ) { return starttime; }
	time_t   getConnectTime   ( void ) { return connecttime; }
	char *   getHost          ( void ) { return host?host:unknown; }
	char *   getOs            ( void ) { return os?os:unknown; }
	char *   getOsRelease     ( void ) { return osrelease?osrelease:unknown; }
	char *   getOsVersion     ( void ) { return osversion?osversion:unknown; }
	char *   getMachine       ( void ) { return machine?machine:unknown; }
	char *   getShell         ( void ) { return shell?shell:unknown; }
	
	void asciiDump ( FILE * fp = stdout )
		{
		fprintf(fp, "--------------------------------------------------------\n");
		fprintf(fp, "                Printing Client Information\n");
		fprintf(fp, "--------------------------------------------------------\n");
		fprintf(fp, "=> USERNAME     : %s\n", username?username:"UNDEFINED");
		fprintf(fp, "=> GROUP        : %s\n", group?group:"UNDEFINED");
		fprintf(fp, "=> USER ID      : %s\n", uid?ltoa(uid):"UNDEFINED");
		fprintf(fp, "=> GROUP ID     : %s\n", gid?ltoa(gid):"UNDEFINED");
		fprintf(fp, "=> PROCESS ID   : %s\n", pid?ltoa(pid):"UNDEFINED");
		fprintf(fp, "=> APPLICATION  : %s\n", program?program:"UNDEFINED");
		fprintf(fp, "=> COMMAND LINE : %s\n", commandline?commandline:"UNDEFINED");
		fprintf(fp, "=> START TIME   : %s",   starttime?ctime(&starttime):"UNKNOWN\n");
		fprintf(fp, "=> CONNECT TIME : %s",   connecttime?ctime(&connecttime):"UNKNOWN\n");
		fprintf(fp, "=> HOST NAME    : %s\n", host?host:"UNKNOWN");
		fprintf(fp, "=> OS           : %s\n", os?os:"UNKNOWN");
		fprintf(fp, "=> OS VERSION   : %s\n", osversion?osversion:"UNKNOWN");
		fprintf(fp, "=> OS RELEASE   : %s\n", osrelease?osrelease:"UNKNOWN");
		fprintf(fp, "=> HARDWARE ID  : %s\n", machine?machine:"UNKNOWN");
		fprintf(fp, "--------------------------------------------------------\n");		
		}
};

	
class ClientInfo 
{
private:
	cdevData data;		
	
public:
	ClientInfo ( void )
		{
		cdevData::addTag("username");
		cdevData::addTag("group");
		cdevData::addTag("uid");
		cdevData::addTag("gid");
		cdevData::addTag("pid");
		cdevData::addTag("program");
		cdevData::addTag("commandline");
		cdevData::addTag("starttime");
		cdevData::addTag("connecttime");
		cdevData::addTag("host");
		cdevData::addTag("os");
		cdevData::addTag("osrelease");
		cdevData::addTag("osversion");
		cdevData::addTag("machine");
		cdevData::addTag("shell");
		cdevData::addTag("sendPktCnt");
		cdevData::addTag("recvPktCnt");
		cdevData::addTag("socket");
		
		#ifndef _WIN32
			struct utsname hostinfo;
			struct group  * grp;
			char * shell = getenv("SHELL");
		
			uname(&hostinfo);
			grp = getgrgid(getgid());

			data.insert("username",  getlogin());
			data.insert("group",     grp?grp->gr_name:(char *)"UNDEFINED");
			data.insert("uid",       (unsigned)getuid());
			data.insert("gid",       (unsigned)getgid());
			data.insert("pid",       (unsigned)getpid());
			data.insert("host",      hostinfo.nodename);
			data.insert("os",        hostinfo.sysname);
			data.insert("osrelease", hostinfo.release);
			data.insert("osversion", hostinfo.version);
			data.insert("machine",   hostinfo.machine);
			data.insert("shell",     shell?shell:(char *)"UNDEFINED");

			#if defined(__hpux)
				struct pst_status pstatData;
				pstat_getproc(&pstatData, sizeof(pstatData), 0, (int)getpid());
				data.insert("program", pstatData.pst_ucomm);
				data.insert("commandline", pstatData.pst_cmd);
				data.insert("starttime", pstatData.pst_start);
			#endif
		#else
			char          userNameBuf[UNLEN+1];
			unsigned long userNameLen = UNLEN;
			char          hostNameBuf[MAXHOSTNAMELEN+1];
			unsigned long hostNameLen = MAXHOSTNAMELEN;
			
			*userNameBuf = 0;
			*hostNameBuf = 0;
			
			data.insert("pid", GetCurrentProcessId());
			if(GetUserName    (userNameBuf, &userNameLen)) data.insert("username", userNameBuf);
			if(GetComputerName(hostNameBuf, &hostNameLen)) data.insert("host", hostNameBuf);
			
			if(userNameBuf && hostNameBuf)
				{
				char          grpNameBuf[GNLEN+1];
				unsigned long grpNameLen = GNLEN;
				char          sidBuf[256];
				unsigned long sidLen     = 256;
				SID_NAME_USE  sidType;
				
				*grpNameBuf = 0;
				if(LookupAccountName(hostNameBuf, userNameBuf, 
						     sidBuf, &sidLen, grpNameBuf,
						     &grpNameLen, &sidType))
					{
					data.insert("group", grpNameBuf);
					}
				}
			
			OSVERSIONINFO osv;
			osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
			if(GetVersionEx   (&osv))
				{
				char osVersionBuf[64];
				switch(osv.dwPlatformId)
					{
					case VER_PLATFORM_WIN32s:
					data.insert("os", "WINDOWS");
					break;
					
					case VER_PLATFORM_WIN32_WINDOWS:
					if(osv.dwMinorVersion == 0)
						data.insert("os", "WINDOWS 95");
					else	data.insert("os", "WINDOWS 98");
					break;
					
					case VER_PLATFORM_WIN32_NT:
					data.insert("os", "WINDOWS NT");
					break;
					
					default:
					data.insert("os", "WIN32");
					break;
					}
				sprintf(osVersionBuf, "%d.%d", osv.dwMajorVersion, osv.dwMinorVersion);
				data.insert("osversion", osVersionBuf);
				data.insert("osrelease", ltoa(osv.dwBuildNumber));
				}
			
			SYSTEM_INFO   sysinfo;
			GetSystemInfo(&sysinfo);
			switch(sysinfo.wProcessorArchitecture)
				{
				case PROCESSOR_ARCHITECTURE_INTEL:
				data.insert("machine", "PROCESSOR_ARCHITECTURE_INTEL");
				break;
					
				case PROCESSOR_ARCHITECTURE_MIPS:
				data.insert("machine", "PROCESSOR_ARCHITECTURE_MIPS");
				break;
					
				case PROCESSOR_ARCHITECTURE_ALPHA:
				data.insert("machine", "PROCESSOR_ARCHITECTURE_ALPHA");
				break;
					
				case PROCESSOR_ARCHITECTURE_PPC:
				data.insert("machine", "PROCESSOR_ARCHITECTURE_PPC");
				break;
					
				case PROCESSOR_ARCHITECTURE_UNKNOWN:
				default:
				data.insert("machine", "PROCESSOR_ARCHITECTURE_UNKNOWN");
				break;
				}
			
			if(__argc>0)
				{
				int    i;
				char * cmdLine = NULL;
				size_t cmdLineLen = 0;
				
				data.insert("program", __argv[0]);
				for(i=0; i<__argc; i++) cmdLineLen+=strlen(__argv[i])+1;
				cmdLine = new char [cmdLineLen];
				*cmdLine = 0;
				for(i=0; i<__argc; i++) 
					{
					strcat(cmdLine, __argv[i]);
					if(i+1<__argc) strcat(cmdLine, " ");
					}
				data.insert("commandline", cmdLine);
				}
			FILETIME startTime;
			FILETIME exitTime;
			FILETIME kernelTime;
			FILETIME userTime;
			if(GetProcessTimes(GetCurrentProcess(), &startTime, &exitTime, &kernelTime, &userTime))
				{
				struct timeval tv;
				FileTimeToTimeVal(&startTime, &tv);
				data.insert("starttime", tv.tv_sec);
				}
		#endif
		}
	
	cdevData & getClientData ( void ) { return data; }

	void asciiDump ( FILE * fp = stdout )
		{
		fprintf(fp, "--------------------------------------------------------\n");
		fprintf(fp, "                Printing Client Information\n");
		fprintf(fp, "--------------------------------------------------------\n");
		
		char *   username;
		char *   group;
		unsigned pid;
		unsigned gid;
		unsigned uid;
		char *   host;
		char *   os;
		char *   osrelease;
		char *   osversion;
		char *   machine;
		char *   shell;
		char *   program;
		char *   commandline;
		long     starttime;
		
		if(data.find("username", (void * &)username)!=CDEV_SUCCESS) username = NULL;
		if(data.find("group",    (void * &)group)!=CDEV_SUCCESS) group = NULL;
		if(data.find("host", (void * &)host)!=CDEV_SUCCESS) host = NULL;
		if(data.find("os", (void * &)os)!=CDEV_SUCCESS) os = NULL;
		if(data.find("osrelease", (void * &)osrelease)!=CDEV_SUCCESS) osrelease = NULL;
		if(data.find("osversion", (void * &)osversion)!=CDEV_SUCCESS) osversion = NULL;
		if(data.find("machine", (void * &)machine)!=CDEV_SUCCESS) machine = NULL;
		if(data.find("shell", (void * &)shell)!=CDEV_SUCCESS) shell=NULL;
		if(data.find("program", (void * &)program)!=CDEV_SUCCESS) program=NULL;
		if(data.find("commandline", (void * &)commandline)!=CDEV_SUCCESS) commandline=NULL;
		if(data.get("starttime", &starttime)!=CDEV_SUCCESS) starttime = 0;
		if(data.get("pid", &pid)!=CDEV_SUCCESS) pid = 0;
		if(data.get("gid", &gid)!=CDEV_SUCCESS) gid = 0;
		if(data.get("uid", &uid)!=CDEV_SUCCESS) uid = 0;
		
		fprintf(fp, "=> USERNAME     : %s\n", username?username:"UNDEFINED");
		fprintf(fp, "=> GROUP        : %s\n", group?group:"UNDEFINED");
		fprintf(fp, "=> USER ID      : %s\n", uid?ltoa(uid):"UNDEFINED");
		fprintf(fp, "=> GROUP ID     : %s\n", gid?ltoa(gid):"UNDEFINED");
		fprintf(fp, "=> PROCESS ID   : %s\n", pid?ltoa(pid):"UNDEFINED");
		fprintf(fp, "=> APPLICATION  : %s\n", program?program:"UNDEFINED");
		fprintf(fp, "=> COMMAND LINE : %s\n", commandline?commandline:"UNDEFINED");
		fprintf(fp, "=> START TIME   : %s",   starttime?ctime(&starttime):"UNKNOWN\n");
		fprintf(fp, "=> HOST NAME    : %s\n", host?host:"UNKNOWN");
		fprintf(fp, "=> OS           : %s\n", os?os:"UNKNOWN");
		fprintf(fp, "=> OS VERSION   : %s\n", osversion?osversion:"UNKNOWN");
		fprintf(fp, "=> OS RELEASE   : %s\n", osrelease?osrelease:"UNKNOWN");
		fprintf(fp, "=> HARDWARE ID  : %s\n", machine?machine:"UNKNOWN");
		fprintf(fp, "--------------------------------------------------------\n");		
		}
};
