/*======================================================*/
/*			WHO Utility			*/
/*======================================================*/
#define NODEBUG 0
#include "who.os"
#include "c:switch.os"
#define BOOLEAN	int

/*======================================================================*/
/*	Change History							*/
/*======================================================================*/
/*	4.0b	3/16/84 add 'log out' and 'write mode' to request list  */
/*		fix test for out of range request.			*/
/*	4.0a	3/12/84 change spool list to terminate on garbage  -jjc */
/*	4.0	Bump up version to greater than ASM program 	   -drb */
/*	1.0d	Redo some of the headings			   -drb */
/*	1.0c    03/09/84 Eliminate some linefeeds from headings,   -drb */
/*		change test for spool not used to less than or =   -drb */
/*		SPWait so garbage does not print out if a CPM      -drb */
/*		partition is converted to the spool partition      -drb */
/*		remove 2 spaces after printing spool record size   -drb */
/*	1.0b    03/02/84 Change test for active user		   -jjc */
/*      1.0a    03/02/84 Fix History and Spool file len output	   -jjc */
/*	1.0	02/15/84 Release for users			   -jjc	*/
/*	0.0c	01/27/84 add who am I function			   -jjc */
/*	0.0b	12/28/83 bios86 calls changed			   -jjc	*/
/*	0.0a	11/17/83 Utility written in C based on Pascal code -jjc	*/ 
/*======================================================================*/

#ifdef NEWFEAT
#define Banner	"Who Version 4.0b For Separated Boot\n"
#else
#define Banner	"Who Version 4.0a For Separated Boot\n"
#endif

/*page*/
#define NoNetMsg	"Your network is not operational.\nPlease check your HiNet master station.\n"
#define User1Msg	"\n                    HiNet Status as of %02d:%02d:%02d\n\n"
#define User1aMsg	"\n                            HiNet Status\n\n"
#define User2Msg	"User No User Name    Login Time   Last Req Time   Request   Status\n"
#define User3Msg	"------- ---------    ----------   -------------   -------   ------\n"
#define User4Msg	"\n%d Network Users\n"

#define Spool1Msg	"\n               HiNet Spool Jobs\n\n"
#define Spool2Msg	"User Name    Spool Time    File Length    Status\n"
#define Spool3Msg	"---------    ----------    -----------    -------\n"
#define Spool4Msg	"\n%d Spool Jobs \n"

#define Hist1Msg	"\n       HiNet Login History as of %02d:%02d:%02d\n\n"
#define Hist1aMsg	"\n                HiNet Login History\n\n"
#define Hist2Msg	"User No User Name    Login Time    Logout Time\n"
#define Hist3Msg	"------- ---------    ----------    -----------\n"
#define Hist4Msg	"\n%d Users Logged In,  "
#define Hist5Msg        "%d Logged Out\n"
#define AmIMsg		"                      This is your login data.\n\n"

/*page*/
#define	MAXusers	32
#define	MAXspools	16
#define NAMELTH	8

struct TIME 
{
	CHAR	sec;
	CHAR	min;
	CHAR	hour;
};

struct DATETIME 
{
	CHAR		FractSecs;
	struct TIME	t;
	CHAR		day [3];
};
/*==============================*/
/*	U S E R   S T A T U S	*/
/*==============================*/
#define	USNotUsed	0
#define USLogIn		0xFF

struct USER 
{
	CHAR		status;
	CHAR		Uname [NAMELTH];
	struct TIME	Login;
	struct TIME	LastAccess;
	CHAR		LastRequest;
};

/*======================================*/
/*	S P O O L E R  S T A T U S	*/
/*======================================*/
#define	SPStart		0
#define SPSpool		1
#define	SPReady		2
#define	SPPrint		3
#define SPDone		4
#define	SPWait		5
#define SPNotUsed	0xE5
struct SPOOLER 
{
	CHAR		status;
	CHAR		userno;
	struct TIME	StartTime;
	CHAR		hicount;
	CHAR		filler2;
	CHAR		lowcount;
	CHAR		Sname [NAMELTH];
};

/*==============================================*/
/*	Global Variables			*/
/*==============================================*/
struct 
{
	struct USER	users [MAXusers];
	struct SPOOLER	spools [MAXspools];
} 
WhoInfo;
struct USER	*UserTab [MAXusers];
int		UserNo  [MAXusers];
struct SPOOLER	*SpoolTab [MAXspools];
BOOLEAN	DoHistory;
BOOLEAN	DoWhoAmI;
BOOLEAN	TimeSet;
struct DATETIME	now;

/*page*/
/*==============================================================*/
/*	GetArgs	- get the arguments from the command line	*/
/*==============================================================*/
GetArgs (argc, argv)
int	argc;
CHAR	*argv [];

{
	DoHistory = FALSE;
	DoWhoAmI = FALSE;
	while (--argc > 0) 
	{
#ifndef NODEBUG
		printf ("Arg <%s>\n", *(argv+1));
#endif
		switch (tolower ((*++argv) [0])) 
		{
		case 'h' :
			DoHistory = TRUE;
			break;
		case 'a' :
			DoWhoAmI = TRUE;
			break;
		}
	}
}

/*page*/
/*==============================================================*/
/*	NormalWho	- prints normal who report		*/
/*==============================================================*/
NormalWho ()

{
	int		i;
	BOOLEAN		FirstTime = TRUE;
	struct USER	**u;
	int		Nusers = 0;
	struct SPOOLER	*p = NULL;
	int		Nspools = 0;

	if (TimeSet)
		printf (User1Msg, now.t.hour, now.t.min, now.t.sec);
	else
		printf (User1aMsg);
	printf (User2Msg);
	printf (User3Msg);

	/*==== Print Users ====*/
	for (i = 0, u = UserTab; i < MAXusers; i++, u++)
		if ((*u)->status != USNotUsed) 
		{
			PrintUser (UserNo [i], *u);
			Nusers++;
		}
	printf (User4Msg, Nusers);

	/*==== Print Spool Jobs ====*/
	for (i = 0, p = WhoInfo.spools; i < MAXspools && p->status <= SPWait; 
		i++, p++)

	{	
		if (FirstTime) 
		{
			printf (Spool1Msg);
			printf (Spool2Msg);
			printf (Spool3Msg);
			FirstTime = FALSE;
		}
		PrintSpool (p);
		Nspools++;
	}
	if (!FirstTime)
		printf (Spool4Msg, Nspools);
}

/*page*/
/*==============================================================*/
/*	PrintLog	- Print User login info			*/
/*==============================================================*/

BOOLEAN PrintLog (uno, u)
int		uno;
struct USER	*u;


{
	BOOLEAN	result;

	printf ("  %02x     ",uno);
	printf ("%-8.8s     ", u->Uname);
	PrintTime (&u->Login);
	if (result = (u->status != USLogIn)) 
	{
		printf ("      ");
		PrintTime (&u->LastAccess);
	}
	putchar ('\n');
	return (!result);
}

/*page*/
/*======================================================*/
/*	PrintRequest	- Decode the request byte into	*/
/*			  display string		*/
/*======================================================*/
#ifdef NEWFEAT
#define	ReqMsgMax	18
#else
#define	ReqMsgMax	16
#endif

CHAR	*ReqMsgTab [ReqMsgMax] = 
{
	"who     ",
	"read    ",
	"write   ",
	"login   ",
	"startspl",
	"read    ",
	"stop spl",
	"assign  ",
	"hog     ",
	"lock    ",
	"unlock  ",
	"clrlock ",
	"spool   ",
	"volstat ",
	"date tim",
#ifdef NEWFEAT
	"log out ",
	"wr  mode",	/* should make all bigger and print write mode */
#endif
	"unknown "
};

PrintRequest(req)
CHAR	req;

{
#ifndef NODEBUG
	printf (" %2x", req);
#endif

	req -= 0x10; /* requests range from 0x10 to 0x1E */
	if (req >= 0 && req < ReqMsgMax)
		printf (ReqMsgTab [req]);
	else
#ifdef NEWFEAT
		printf (ReqMsgTab [ReqMsgMax-1]);
#else
		printf (ReqMsgTab [ReqMsgMax]);
#endif
}

/*page*/
/*==============================================================*/
/*	PrintSpool - prints entry in spool table list		*/
/*==============================================================*/

PrintSpool (p)
struct SPOOLER	*p;

{
	int	FileSize;
	struct TIME	*t;

	printf ("%-8.8s", p->Sname);
	printf ("      ");
	PrintTime (&p->StartTime);

	FileSize = ((p->hicount & 0x0f) *128) + (p->lowcount - 2);

	printf ("  ");
	if (FileSize == 1)
		printf ("     1 record  ");
	else
		printf ("%6d records ", FileSize);
	printf ("   ");
	PrintSpStatus (p->status);
#ifndef NODEBUG
	printf (" %x %x ", p->userno, p->filler2);
#endif
	putchar ('\n');
}

/*page*/
/*==============================================================*/
/*	PrintSpStatus	- Print the spool status		*/
/*==============================================================*/
#define	SpStMax	7
CHAR	*SpStMsgTab [SpStMax] = 
{
	"starting",
	"spooling",
	"ready   ",
	"printing",
	"finished",
	"waiting ",
	"unknown "
};

PrintSpStatus (stat)
CHAR	stat;

{
	if (stat >= 0 && stat < SpStMax)
		printf (SpStMsgTab [stat]);
	else
		printf (SpStMsgTab [SpStMax]); 
}

/*page*/
/*==============================================================*/
/*	PrintTime	- Print the time			*/
/*==============================================================*/
PrintTime (t)
struct TIME	*t;

{
	if (t->hour == ' ' && t->min == ' ' && t->sec == ' ')
		printf ("        ");
	else
		printf ("%02d:%02d:%02d", t->hour, t->min, t->sec);
}

/*page*/
/*==============================================================*/
/*	PrintUser	- prints info for an active user	*/ 
/*==============================================================*/

PrintUser (uno, u)
int		uno; /* User number */

struct USER	*u;

{
	printf ("  %02x     ",uno);
	printf ("%-8.8s     ", u->Uname);
	PrintTime (&u->Login);
	printf ("      ");
	PrintTime (&u->LastAccess);
	printf ("      ");
	PrintRequest (u->LastRequest);
	printf ("  ");
	PrintUsrStatus (u->status);
	putchar ('\n');
}

/*page*/
/*==============================================================*/
/*	PrintUsrStatus	- print status				*/
/*==============================================================*/

PrintUsrStatus (stat)
CHAR	stat;

{
	printf (stat == USLogIn ? "active     "
	    : "logging out");
}

/*page*/
/*==============================================================*/
/*	SortSpools	- sort spool names			*/
/*==============================================================*/
SortSpools ()

{
	int		gap, i, j;
	struct SPOOL	*stmp;

#ifndef NODEBUG
	printf ("Starting sort of spool names...");
#endif 

	for (i = 0; i < MAXspools; i++)
		SpoolTab [i] = &WhoInfo.spools [i];

	for (gap = MAXspools/2; gap > 0; gap /= 2)
		for (i = gap; i < MAXspools; i++)
			for (j = i-gap; j >= 0; j -= gap) 
			{
				if (strncmp (SpoolTab [j]->Sname, 
				SpoolTab [j + gap]->Sname, NAMELTH) <= 0)
					break;

				stmp = SpoolTab [j];
				SpoolTab [j] = SpoolTab [j + gap];
				SpoolTab [j + gap] = stmp;
			}

#ifndef NODEBUG
	printf ("sort finished\n");
#endif
}

/*page*/
/*==============================================================*/
/*	SortUsers	- sorts an array of pointers to Users	*/
/*==============================================================*/
SortUsers ()

{
	int		gap, i, j;
	struct USER	*utmp;
	int		itmp;

#ifndef NODEBUG
	printf ("Starting sort of user names...");
#endif 

	for (i = 0; i < MAXusers; i++) 
	{
		UserTab [i] = &WhoInfo.users [i];
		UserNo [i] = i;
	}

	for (gap = MAXusers/2; gap > 0; gap /= 2)
		for (i = gap; i < MAXusers; i++)
			for (j = i-gap; j >= 0; j -= gap) 
			{
				if (strncmp (UserTab [j]->Uname, 
				UserTab [j + gap]->Uname, NAMELTH) <= 0)
					break;

				utmp = UserTab [j];
				UserTab [j] = UserTab [j + gap];
				UserTab [j + gap] = utmp;

				itmp = UserNo [j];
				UserNo [j] = UserNo [j + gap];
				UserNo [j + gap] = itmp;
			}

#ifndef NODEBUG
	printf ("sort finished\n");
#endif
}

/*page*/
/*==============================================================*/
/*	WhoAmI		- Do 'Who am I' report			*/
/*==============================================================*/

WhoAmI ()

{
#define	UNO	23
	CHAR	info_buf [38];
	int	n;


	if (TimeSet)
		printf (User1Msg, now.t.hour, now.t.min, now.t.sec);
	else
		printf (User1aMsg);
	printf (AmIMsg);
	printf (User2Msg);
	printf (User3Msg);

	GetDMSInfo (info_buf);

	n = info_buf [UNO];
	PrintUser (n, &WhoInfo.users [n]);

}	

/*page*/
/*==============================================================*/
/*	WhoHistory	- Do login history report		*/
/*==============================================================*/

WhoHistory ()

{
	int		i;
	struct USER	**u;
	int		Nlogin  = 0;
	int		Nlogout = 0;

	if (TimeSet)
		printf (Hist1Msg, now.t.hour, now.t.min, now.t.sec);
	else
		printf (Hist1aMsg);
	printf (Hist2Msg);
	printf (Hist3Msg);

	/*==== Print History of User Logins ====*/
	for (i = 0, u = UserTab; i < MAXusers; i++, u++)
		if ((*u)->LastRequest != 0x20) /*logout request */
			if (PrintLog (UserNo [i], *u))
				Nlogin++;
			else
				Nlogout++;
		else if ((*u)->status != USNotUsed)
			if (PrintLog (UserNo [i], *u))
				Nlogin++;
			else
				Nlogout++;
	printf (Hist4Msg, Nlogin);
	printf (Hist5Msg, Nlogout);
}

/*page*/
/*======================================================================*/
/*				M A I N					*/
/*======================================================================*/
main (argc, argv)
int	argc;
CHAR	*argv []; 

{
	GetArgs (argc, argv);

#ifndef NODEBUG
	if (DoHistory)
		printf ("Doing Login History\n");
	if (DoWhoAmI)
		printf ("Doing Who am I\n");
#endif

	printf (Banner); 
	TimeSet = (GetDateTime (&now) == 0 
	    && strncmp ((CHAR *) &now, "       ", 7) != 0);

#ifndef NODEBUG
	if (TimeSet) 
		printf ("The Time is Set\n");
	printf ("Current Time = %02d:%02d:%02d\n", 
	now.t.hour, 
	now.t.min, 
	now.t.sec);
#endif

	if (GetWho (&WhoInfo) == 0)
		if (!(DoHistory || DoWhoAmI)) 
		{
			SortUsers ();
			SortSpools ();
			NormalWho ();
		}
		else 
		{
			if (DoHistory) 
			{
				SortUsers ();
				WhoHistory ();
			}
			if (DoWhoAmI)
				WhoAmI ();
		}
	else
		/*========================*/
		/* get of who info failed */
		/*========================*/
		printf (NoNetMsg);


} /* end of main */



