// ===========================================================================
//	UAMUtils.cp 				© 1997 Microsoft Corp. All rights reserved.
// ===========================================================================
// General utilities used by the Microsoft User Authentication Method.
//
// ===========================================================================

#include <Errors.h>
#include <String.h>
#include <stdio.h>

#include "UAMDebug.h"
#include "UAMUtils.h"
#include "UAMNetwork.h"
#include "UAMDialogs.h"

// ---------------------------------------------------------------------------
//		¥ UAM_PStrCopy()
// ---------------------------------------------------------------------------
//	Custom routine for copying pascal style strings. Copies inSrcString into
//	inDestString. Careful here since this routine doesn't know how long a
//	string can be, don't copy a 255 byte string into a 32 byte string. BOOM!

void UAM_PStrCopy(const StringPtr inSrcString, StringPtr inDestString)
{
	Assert_(inSrcString  != NULL);
	Assert_(inDestString != NULL);
	
	BlockMove(inSrcString, inDestString, inSrcString[0] + 1);
	inDestString[0] = inSrcString[0];
}


// ---------------------------------------------------------------------------
//		¥ UAM_AppendPStr()
// ---------------------------------------------------------------------------
//	Custom routine for appending one pascal style string to another.
//	inAppendStr in pasted to the end of inBase. inDestSize if the maximum size
//	the new string can be.

void UAM_AppendPStr(Str255 inBase, const Str255 inAppendStr, short inDestSize)
{
	Assert_(inBase		!= NULL);
	Assert_(inAppendStr	!= NULL);
	Assert_(inDestSize 	>  0);
	
	short	charsToCopy	= inAppendStr[0];
	
	if ((inBase[0] + charsToCopy) > (inDestSize - 1)) {
		charsToCopy = inDestSize - 1 - inBase[0];
	}
	
	BlockMove(inAppendStr + 1, inBase + inBase[0] + 1, charsToCopy);
	
	inBase[0] += charsToCopy;
}

#pragma mark-
// ---------------------------------------------------------------------------
//		¥ UAM_FrontWindowRect()
// ---------------------------------------------------------------------------
//	Returns the rect of the front-most window is global coordinates.

void UAM_FrontWindowRect(Rect *outWindowRect)
{
	WindowPtr	theWindow = FrontWindow();
	Point		thePoint;
	Rect		theRect;
		
	theRect 		= theWindow->portRect;
	
	thePoint.h 		= theWindow->portRect.left;
	thePoint.v 		= theWindow->portRect.top;
	
	LocalToGlobal(&thePoint);
	theRect.left	= thePoint.h;
	theRect.top		= thePoint.v;
	
	thePoint.h 		= theWindow->portRect.right;
	thePoint.v 		= theWindow->portRect.bottom;
	
	LocalToGlobal(&thePoint);
	theRect.right	= thePoint.h;
	theRect.bottom	= thePoint.v;
	
	*outWindowRect = theRect;
}


// ---------------------------------------------------------------------------
//		¥ UAM_GetUserName()
// ---------------------------------------------------------------------------
//	Returns the default user name as set in the Sharing Setup/File Sharing
//	dialogs. This would also be considered the old 'Chooser' name.

void UAM_GetUserName(StringPtr outUserName)
{
	StringHandle	theString = NULL;
	
	outUserName[0] = 0;
		
	theString = GetString(STR_ChooserUserName);
	if (theString != NULL)
	{
		UAM_PStrCopy(*theString, outUserName);
	}
}


// ---------------------------------------------------------------------------
//		¥ UAM_GetWorkStationName()
// ---------------------------------------------------------------------------
//	Returns the workstation name as set in the Sharing Setup/File Sharing
//	dialogs.

void UAM_GetWorkStationName(Str255 outWSName)
{
	StringHandle	theString = NULL;
	
	outWSName[0] = 0;
	
	theString = GetString(STR_Sys7WorkStationName);
	if (theString != NULL)
	{
		HLock((Handle)theString);
		UAM_PStrCopy(*theString, outWSName);
		HUnlock((Handle)theString);
	}
}


// ---------------------------------------------------------------------------
//		¥ UAM_AFPClientSupportsOurUAM
// ---------------------------------------------------------------------------
//	Returns TRUE if the client we're on is running AppleShare Client 3.8
//	or later.

Boolean UAM_AFPClientSupportsOurUAM(void)
{
	short 	theCfgWord;
	short	theVersion = UAM_AppleShareVersion(&theCfgWord);
	
	if (theVersion <= gestaltAFPClient3_7_2)
	{
		StopAlert(ALRT_WrongClientVers, NULL);
		return(false);
	}
	
	return(true);
}


#pragma mark-
// ---------------------------------------------------------------------------
//		¥ UAM_VersionString
// ---------------------------------------------------------------------------
//	Returns a string containing the version of this build.

void UAM_VersionString(Str32 outVersionString)
{
	Handle			theVersHandle;
	long			theVersion;
	unsigned char	theVer1, theVer2, theVer3, theRelStatus, thePrereleaseNum;
	Str32			theTempStr;
	
	outVersionString[0] = 0;
	UAM_PStrCopy("\pv", outVersionString);
	
	theVersHandle = Get1Resource('vers', 1);
	if (theVersHandle)
	{
		theVersion = *((long *)(*theVersHandle));
	
		ReleaseResource(theVersHandle);
	
		theVer1		= ((char *)&theVersion)[0];
		theVer1		= (((theVer1 & 0xF0) >> 4) * 10) + (theVer1 & 0x0F);
		theVer2		= (((char *)&theVersion)[1] & 0xF0) >> 4;
		theVer3		= (((char *)&theVersion)[1] & 0x0F);
		
		theRelStatus		= ((char *)&theVersion)[2];
		thePrereleaseNum	= ((char *)&theVersion)[3];
		
		NumToString((long)theVer1, theTempStr);
		UAM_AppendPStr(outVersionString, theTempStr, sizeof(Str32));
		UAM_AppendPStr(outVersionString, "\p.", sizeof(Str32));
		
		NumToString((long)theVer2, theTempStr);
		UAM_AppendPStr(outVersionString, theTempStr, sizeof(Str32));
	
		if (theVer3 != 0)
		{
			UAM_AppendPStr(outVersionString, "\p.", sizeof(Str32));
			
			NumToString((long)theVer3, theTempStr);
			UAM_AppendPStr(outVersionString, theTempStr, sizeof(Str32));
		}
		
		switch(theRelStatus)
		{
			case 0x20:
				UAM_AppendPStr(outVersionString, "\pd", sizeof(Str32));
				break;
			
			case 0x40:
				UAM_AppendPStr(outVersionString, "\pa", sizeof(Str32));
				break;
	
			case 0x60:
				UAM_AppendPStr(outVersionString, "\pb", sizeof(Str32));
				break;
				
			default:
				break;
		}
		
		if (theRelStatus != 0x80)
		{
			NumToString((long)thePrereleaseNum, theTempStr);
			UAM_AppendPStr(outVersionString, theTempStr, sizeof(Str32));
		}
	}
}


// ---------------------------------------------------------------------------
//		¥ UAM_GetAFPInfo
// ---------------------------------------------------------------------------
//	Return the AFP version string and the default user name.

void UAM_GetAFPVersionString(	AFPSrvrInfo 			*inInfo,
								ClientUAMCallbackRec 	*inCallbacks,
								Str32					&ioAFPVersion,
								Str32					&ioDefaultUserName	)
{
	struct 		AFPClientInfo *theClientInfo = NULL;
	short		theIndex;
	StringPtr	theVersionBuf;
	UInt32		theVersionBufSize;
	Boolean		theResult;
	
	#if GENERATING68K
	OSStatus 	theError;
	#endif
	
	Assert_(inCallbacks 		!= NULL);
	Assert_(inInfo 				!= NULL);
	Assert_(ioAFPVersion		!= NULL);
	Assert_(ioDefaultUserName	!= NULL);
			
	ioAFPVersion[0]	  	 = 0;
	ioDefaultUserName[0] = 0;
	
	if ((inCallbacks) && (inInfo))
	{
		//
		//Use the UAM callback GetClientInfo() to get the client info.
		//
		#if GENERATING68K
		theError = inCallbacks->GetClientInfoUPP(kAFPClientInfo, (ClientInfo **)&theClientInfo);
		if (theError != noErr)
		{
			UAM_ReportError(theError);
			return;
		}
		#else
		CallUniversalProc(	inCallbacks->GetClientInfoUPP,
							kGetClientInfoProcInfo,
							kAFPClientInfo,
							(ClientInfo **)&theClientInfo	);
		#endif
		
		Assert_(theClientInfo != NULL);
		
		if (theClientInfo)
		{
			//
			//Stuff the default user name in the return parameter.
			//
			UAM_PStrCopy(theClientInfo->fDefaultUserName, ioDefaultUserName);
			
			//
			//Go through the list of AFP versions supported on this client
			//and try to find them in the SrvrInfoBuffer, first match
			//succeeds.
			//
			
			theVersionBuf		= (StringPtr)((UInt32)inInfo + inInfo->fVerCountOffset + 1);
			theVersionBufSize	= (inInfo->fUAMCountOffset - inInfo->fVerCountOffset) - 1;
			
			for (theIndex = 0; theIndex < theClientInfo->fNumAFPVersions; theIndex++)
			{
				theResult = UAM_FindStringInBuffer(
										theClientInfo->fAFPVersionStrs[theIndex],
										theVersionBuf,
										theVersionBufSize  );
				
				if (theResult)
				{
					UAM_PStrCopy(theClientInfo->fAFPVersionStrs[theIndex], ioAFPVersion);
					return;
				}
			}
		}
	}
}


// ---------------------------------------------------------------------------
//		¥ UAM_FindStringInBuffer
// ---------------------------------------------------------------------------
//	Finds a pascal string within a buffer.

Boolean UAM_FindStringInBuffer(StringPtr inString, StringPtr inBuffer, short inBufferSize)
{
	short	i = 0;
	short	theLen;
	
	theLen = inBuffer[i];
	
	while(TRUE)
	{
		if (memcmp(&inBuffer[i], inString, theLen + 1) != 0)
		{
			i += theLen + 1;
			theLen = inBuffer[i];
			
			if (i >= inBufferSize)
				break;
		}
		else {
			return(TRUE);
		}
	}
	
	return(FALSE);
}


// ---------------------------------------------------------------------------
//		¥ UAM_AppleShareVersion()
// ---------------------------------------------------------------------------
//	Returns the version of AppleShare running on the host computer.

short UAM_AppleShareVersion(short *upperWord)
{
	long	theResult;
	OSErr	theError;
	
	theError = Gestalt(gestaltAFPClient, &theResult);
	if (!theError)
	{
		if (upperWord != NULL) {
			*upperWord = (theResult & gestaltAFPClientAttributeMask);
		}
		
		return(theResult & gestaltAFPClientVersionMask);
	}
	
	return(0);
}


// ---------------------------------------------------------------------------
//		¥ UAM_KeyDown()
// ---------------------------------------------------------------------------
//	Returns TRUE if the passed keycode is currently held down.

Boolean UAM_KeyDown(Int16 inKeycode)
{
	KeyMapByteArray	theKeyMap;
	
	GetKeys((UInt32*)theKeyMap);
	return((theKeyMap[inKeycode>>3] >> (inKeycode & 7)) & 1);
}