
/* FAME WHO Door
 * ~~~~~~~~~~~~~
 *
 * $VER:FAMEWHO.FIM v1.1
 *
 * FAMEWHO.FIM is a replacement door for MainPart's internal WHO!
 *
 * Door coded by David 'Strider/tRSi' Wettig e-mail: strider@deadline.snafu.de
 *
 * Design and idea by sCANDIC/dCN.
 *
 * Used tab size: 2
 */

char *VerStr={"$VER:FAMEWHO.FIM v1.1 "__AMIGADATE__};

/* Includes:
 */

#include <FAME/FAMEPublic.h>

/* Structures:
 */

struct	WHOList {
struct	WHOList	*whol_Next;
char						whol_UserName[32],
								whol_Location[32],
								whol_SVAction[22],
								whol_FileUpload[32],
								whol_FileDownload[32],
								whol_XferProt[32];
long						whol_SVNodeNumber,
								whol_UploadCPS,
								whol_DownloadCPS,
								whol_BaudRate,
								whol_InitBaud;
};

/* Global variables:
 */

struct	Library				*UtilityBase	= NULL;
struct	WHOList				*FirstWHOList	= NULL,
											*LastWHOList	= NULL;
struct	FAMEInfoList	*TNFInfoList	= NULL;
short		int						ForceWhoFlag	= 0;
long									NodeNr;

/* Some buffers:
 */

char	WorkStr[256],
			DummyBuf[256],
			NodeNrBuf[12],
			BaudBuffer[22];

/* Disable Lattice CTRL-C handling:
 */

#ifdef LATTICE
int CXBRK(void) {return(0);}
int chkabort(void) {return(0);}
#endif

/* Prototypes:
 */

short int WHOAddList(struct FAMEInfoList *MyFAMEInfoList);
void StartIntWHO(void);
void ShutDown(int code);

/* main() entry point:
 */

void main(int argc, char *argv[])
{
	/* FAMESemaphore:
	 */

	struct  FAMESemaphore *MyFAMESemaphore;

  if(argc < 2) {

    printf("\nSorry, %s is a Door and must be called from FAME BBS!\n\n",argv[0]);
    exit(RETURN_ERROR);
  }

	NodeNr = FAMEAtol(argv[1]);

  SPrintf((STRPTR)FAMEDoorPort,"FAMEDoorPort%ld",NodeNr);

  if(PortStart())
		PortEnd(40);

	/* Open utility.library, needed for Stricmp:
	 */

	if( ! (UtilityBase = (struct Library *) OpenLibrary("utility.library",37L)))
		ShutDown(RETURN_FAIL);

	/* Version check:
	 */

	GetCommand(WorkStr,0,0,0,SR_FAMEVersion);

	if(MyFAMEDoorMsg -> fdom_Data2 < 1 || (MyFAMEDoorMsg -> fdom_Data2 == 1 && MyFAMEDoorMsg -> fdom_Data3 < 13)) {

		PutString("\r\n[33mSoory[m, [33myou need at least MainPart v[33m1[m.[33m13 to use FAMEWHO.FIM v[33m1[m.[33m1 [m!\r\n\n[36mStarting internal WHO instead[m...",1);

		Delay(100);

		StartIntWHO();
	}

	/* Get some arguments:
	 */

	GetCommand(WorkStr,0,0,0,NR_GetArgument1);

	if( ! Stricmp(WorkStr,"FORCE"))
		ForceWhoFlag = 1;
	else if( ! Stricmp(WorkStr,"U"))
		StartIntWHO();

	GetCommand(WorkStr,0,0,0,NR_GetArgument2);

	if( ! Stricmp(WorkStr,"FORCE"))
		ForceWhoFlag = 1;
	else if( ! Stricmp(WorkStr,"U"))
    StartIntWHO();

	/* Try to find and obtain the FAMESemaphore:
	 * The name is always 'FAMESemaphore'.
	 */

	Forbid();

	if(MyFAMESemaphore = (struct FAMESemaphore *)FindSemaphore("FAMESemaphore")) {

		struct	FAMEInfoList	*MyFAMEInfoList;

		ObtainSemaphore((struct SignalSemaphore *)MyFAMESemaphore);
		Permit();

		/* Now let's try to get our own pointer:
		 */

		if(TNFInfoList = MyFAMESemaphore -> fsem_FirstNode) {

			long NodeCounter = 0;

			while(TNFInfoList && NodeCounter < NodeNr)
			{
				TNFInfoList = TNFInfoList -> fili_Next;

				NodeCounter ++;
			}

			/* Got our Node ?
			 */

			if(NodeCounter != NodeNr)
				TNFInfoList = NULL;
		}

		/* Now lets read it's data into our own list to lock the FAMESemaphore
		 * as short as possible:
		 */

		if(MyFAMEInfoList = MyFAMESemaphore -> fsem_FirstNode) {

			do
			{
				/* Now give the FAMEInfoList structure to our WHOAddList():
				 */

				if( ! WHOAddList(MyFAMEInfoList))
					break;
			}
			while(MyFAMEInfoList = MyFAMEInfoList -> fili_Next);
		}

		/* We now can/should/must release the FAMESemaphore:
		 */

		ReleaseSemaphore((struct SignalSemaphore *)MyFAMESemaphore);

		/* Now let's do the WHO:
		 *
		 * Note that PutString uses AR_SendStr which will not use the
		 * struct FAMEDoorMsg fdom_IOString[202] !
		 * It will use the fdom_StringPtr and because of this we can have endless
		 * length strings here.
		 * Beware! Do not use strings longer than 201 bytes with PutStringFormat!
		 * PutStringFormat uses fdom_IOString[202] to format into it!
		 */

		PutString("\f\r\n[33m  Node  [mHandle[35m/[36mLocation        [mAction[35m([ms[35m)        [1m_[m                     Baud\r\n[1;34m.----------------------------.-----------------[35m\\[36m/[34m------------------.---------.",0);

		/* We need LastWHOList, because it's no longer needed.
		 * Beware! If you must call WHOAddList later again use a new temporäry
		 * struct WHOList pointer instead!!!
		 */

		LastWHOList = FirstWHOList;

		while(LastWHOList)
		{
			/* Upload instead action?
			 */

			SPrintf(NodeNrBuf,"%ld",LastWHOList -> whol_SVNodeNumber);
			if(strlen(NodeNrBuf) < 2)
				SPrintf(NodeNrBuf,"0%ld",LastWHOList -> whol_SVNodeNumber);

			FAMENumToStr(LastWHOList -> whol_InitBaud,FNSF_GROUPING|FNSF_NUMLOCALE,0,WorkStr);
			FAMENumToStr(LastWHOList -> whol_BaudRate,FNSF_GROUPING|FNSF_NUMLOCALE,0,BaudBuffer);

			if(LastWHOList -> whol_FileUpload[0] || LastWHOList -> whol_FileDownload[0]) {

				if(LastWHOList -> whol_FileUpload[0]) {

					PutStringFormat("\r\n| [0;33m %-4s [m%-20s [1;34m| [m%s %-16s  [32m%5ld cps [1;34m| [m%7s [1;34m|",NodeNrBuf,LastWHOList -> whol_UserName,LastWHOList -> whol_XferProt,LastWHOList -> whol_FileUpload,LastWHOList -> whol_UploadCPS,WorkStr);

					if(LastWHOList -> whol_FileDownload[0])
						PutStringFormat("\r\n| [0;36m%-26s [1;34m| [m%s %-16s  [32m%5ld cps [1;34m| [m%7s [1;34m|",LastWHOList -> whol_Location,LastWHOList -> whol_XferProt,LastWHOList -> whol_FileDownload,LastWHOList -> whol_DownloadCPS,BaudBuffer);
					else
						PutStringFormat("\r\n| [0;36m%-26s [1;34m|[37C| [m%7s [1;34m|",LastWHOList -> whol_Location,BaudBuffer);
				} else {

					PutStringFormat("\r\n| [0;33m %-4s [m%-20s [1;34m| [m%s %-16s  [32m%5ld cps [1;34m| [m%7s [1;34m|",NodeNrBuf,LastWHOList -> whol_UserName,LastWHOList -> whol_XferProt,LastWHOList -> whol_FileDownload,LastWHOList -> whol_DownloadCPS,WorkStr);
					PutStringFormat("\r\n| [0;36m%-26s [1;34m|[37C| [m%7s [1;34m|",LastWHOList -> whol_Location,BaudBuffer);
				}
			} else {

				PutStringFormat("\r\n| [0;33m %-4s [m%-20s [1;34m| [m%-35s [1;34m| [m%7s [1;34m|",NodeNrBuf,LastWHOList -> whol_UserName,LastWHOList -> whol_SVAction,WorkStr);
				PutStringFormat("\r\n| [0;36m%-26s [1;34m|[37C| [m%7s [1;34m|",LastWHOList -> whol_Location,BaudBuffer);
			}

			/* Ok, next one:
			 */

			if(LastWHOList = LastWHOList -> whol_Next)
				PutString("\r\n|----------------------------+-------------------------------------+---------|",0);
		}

		PutString("\r\n`----------------------------·-----------------------------[35m\\[36m/[34m------·---------'[m\r\n\n",0);

	} else
		Permit();


	/* Ending Door!
	 */

	ShutDown(0);
}

/* Generate our list:
 */

short int WHOAddList(struct FAMEInfoList *MyFAMEInfoList)
{
	if(MyFAMEInfoList) {

	  if( ! FirstWHOList) {

			if( ! (FirstWHOList = AllocVec(sizeof(struct WHOList),MEMF_PUBLIC | MEMF_CLEAR)))
				return(FALSE);

			LastWHOList = FirstWHOList;
		} else {

			if( ! (LastWHOList -> whol_Next = AllocVec(sizeof(struct WHOList),MEMF_PUBLIC | MEMF_CLEAR)))
				return(FALSE);

			LastWHOList = LastWHOList -> whol_Next;
		}

		/* Node must be online, else some pointers are invalid!!!
		 */

		if(MyFAMEInfoList -> fili_SVNodeOnline) {

			/* User online?
			 */

			if(MyFAMEInfoList -> fili_UserOnline == 2) {	// Online

				/* Transfer in progress?
				 */

				/* Bi-directional Hydra in usage?
				 */

				if(MyFAMEInfoList -> fili_SVActionCmd == FAME_HYDRA) {

					Forbid();
					FAMEStrCopy(MyFAMEInfoList -> fili_FileUpload,WorkStr,12);
					Permit();
					strcpy(LastWHOList -> whol_FileUpload,"UL: ");
					strcat(LastWHOList -> whol_FileUpload,WorkStr);

					Forbid();
					FAMEStrCopy(MyFAMEInfoList -> fili_FileDownload,WorkStr,12);
					Permit();
					strcpy(LastWHOList -> whol_FileDownload,"DL: ");
					strcat(LastWHOList -> whol_FileDownload,WorkStr);

					strcpy(LastWHOList -> whol_XferProt,"  HYDRA");

					/* Note the (* ) !!! We need this, because fili_UploadCPS is a pointer!
					 */

					LastWHOList -> whol_UploadCPS			= (*MyFAMEInfoList -> fili_UploadCPS);

					/* Note the (* ) !!! We need this, because fili_DownloadCPS  is a pointer!
					 */

					LastWHOList -> whol_DownloadCPS		= (*MyFAMEInfoList -> fili_DownloadCPS);

				} else if(MyFAMEInfoList -> fili_SVActionCmd == FAME_UPLOAD || MyFAMEInfoList -> fili_SVActionCmd == FAME_DOWNLOAD) {

					/* We have a uni-directional xpr transfer:
					 */

					char *Temp;

					if(MyFAMEInfoList -> fili_SVActionCmd == FAME_UPLOAD) {

						Forbid();
						FAMEStrCopy(MyFAMEInfoList -> fili_FileUpload,WorkStr,12);
						Permit();
						strcpy(LastWHOList -> whol_FileUpload,"UL: ");
						strcat(LastWHOList -> whol_FileUpload,WorkStr);

						/* Note the (* ) !!! We need this, because fili_UploadCPS is a pointer!
						 */

						LastWHOList -> whol_UploadCPS			= (*MyFAMEInfoList -> fili_UploadCPS);
					} else {

						Forbid();
						FAMEStrCopy(MyFAMEInfoList -> fili_FileDownload,WorkStr,12);
						Permit();
						strcpy(LastWHOList -> whol_FileDownload,"DL: ");
						strcat(LastWHOList -> whol_FileDownload,WorkStr);

						/* Note the (* ) !!! We need this, because fili_DownloadCPS  is a pointer!
						 */

						LastWHOList -> whol_DownloadCPS		= (*MyFAMEInfoList -> fili_DownloadCPS);
					}

					/* Cut the .library and uppercase:
					 */

					Forbid();
					strcpy(WorkStr,MyFAMEInfoList -> fili_XferProt);
					Permit();

					if(Temp = FAMEStrChrCase(WorkStr,'.'))
						*Temp = '\0';

					FAMEStrCopy(strupr(WorkStr),LastWHOList -> whol_XferProt,7);
				}

				Forbid();
				strcpy(LastWHOList -> whol_UserName,MyFAMEInfoList -> fili_NodeRUser -> UserName);
				strcpy(LastWHOList -> whol_Location,MyFAMEInfoList -> fili_NodeRUser -> UserLocation);
				strcpy(LastWHOList -> whol_SVAction,MyFAMEInfoList -> fili_SVAction);
				Permit();

				LastWHOList -> whol_UserName[20] = '\0';
				LastWHOList -> whol_Location[26] = '\0';

				/* Note the (* ) !!! We need this, because fili_BaudRate is a pointer!
				 */

				LastWHOList -> whol_BaudRate			= (*MyFAMEInfoList -> fili_BaudRate);

			} else {

				/* Else Awaiting Call or Connecting, we left whol_FileUpload,
				 * whol_FileDownload and whol_XferProt blank.
				 * They are cleared from allocation with MEMF_CLEAR.
				 */

				strcpy(LastWHOList -> whol_UserName,"Not available");
				strcpy(LastWHOList -> whol_Location,"Not available");

				if(MyFAMEInfoList -> fili_UserOnline == 1)
					strcpy(LastWHOList -> whol_SVAction,"Connecting");
				else if(MyFAMEInfoList -> fili_UserOnline == 3)
					strcpy(LastWHOList -> whol_SVAction,"Reseting Node");
				else
					strcpy(LastWHOList -> whol_SVAction,"Node awaits a Call");
			}

			/* Note the (* ) !!! We need this, because fili_InitBaud is a pointer!
			 */

			LastWHOList -> whol_InitBaud			= (*MyFAMEInfoList -> fili_InitBaud);

			/* Check for ForceWHO:
			 */

			if(TNFInfoList) {

				if((TNFInfoList -> fili_BitFlags & FILI_FORCEWHO) && (ForceWhoFlag || (TNFInfoList -> fili_NodeRUser -> UserFlags1 & UD_AUTOFORCEONWHO)))
					ForceWhoFlag = 1;
				else
					ForceWhoFlag = 0;
			} else
				ForceWhoFlag = 0;

			if( ! ForceWhoFlag) {

				/* Check for (real) hidden user:
				 */

				if(((MyFAMEInfoList -> fili_BitFlags & FILI_QUIETNODE) || (MyFAMEInfoList -> fili_BitFlags & FILI_USERHIDE)) && Stricmp(MyFAMEInfoList -> fili_NodeRUser -> UserName,"-")) {

					if(MyFAMEInfoList -> fili_BitFlags & FILI_USERREALHIDE) {

						strcpy(LastWHOList -> whol_UserName,"Not available");
						strcpy(LastWHOList -> whol_Location,"Not available");
						strcpy(LastWHOList -> whol_SVAction,"Node awaits a Call");
						LastWHOList -> whol_BaudRate = 0;
					} else {

						strcpy(LastWHOList -> whol_UserName,"Hidden");
						strcpy(LastWHOList -> whol_Location,"Do not disturb!");
					}
				}
			}
		} else {

			/* Node not online:
			 */

			strcpy(LastWHOList -> whol_UserName,"Not available");
			strcpy(LastWHOList -> whol_Location,"Not available");
			strcpy(LastWHOList -> whol_SVAction,"Node not online");
		}

		/* fili_SVNodeNumber will be in every case available.
		 */

		LastWHOList -> whol_SVNodeNumber	= MyFAMEInfoList -> fili_SVNodeNumber;

	  return(TRUE);
	}
	return(FALSE);
}

void StartIntWHO(void)
{
	GetCommand(DummyBuf,0,0,0,NR_GetFullArg);

	SPrintf(WorkStr,"WHO %s",DummyBuf);

	PutCommand(WorkStr,0,0,0,CF_InternalCmd);

	PutString("",1);

	ShutDown(0);
}

/* Shutdown:
 */

void ShutDown(int error)
{
	/* Free our list:
	 * Wee used LastWHOList also, because it's no longer used here.
	 */

	while(FirstWHOList)
	{
		LastWHOList = FirstWHOList -> whol_Next;
		FreeVec(FirstWHOList);
		FirstWHOList = LastWHOList;
	}

	if(UtilityBase)
		CloseLibrary((struct Library *)UtilityBase);

  PortEnd(error);
}

