/*

			Utility functions
			
*/

#include "netfone.h"

//  RSTRING  --  Retrieve a string from the resource file.

char *rstring(int resid)
{
#define maxCStrings 10              // Maximum concurrently used strings
#define maxCSLength 256				// Maximum length of resource strings
    static char rstrings[maxCStrings][maxCSLength];
    static int n = 0;
    int m = n;

#ifdef COUNT_RSTRING
	static DWORD callCount = 0;
	static int reCurso = 0;
	
	callCount++;
	if (!reCurso) {
		reCurso = TRUE;
		propeller(IDC_PH_PACKET_SIZE, callCount);
		reCurso = FALSE;
	}
#endif
    if (LoadString(hInst, resid, rstrings[m], maxCSLength - 1) <= 0) {
        strcpy(rstrings[m], "");
    }
    n = (n + 1) % maxCStrings;
    return rstrings[m];
}

/*	RFILTER  --  Load a filter from the resource file and convert
				 vertical bars to zero characters.  */
				 
char *rfilter(int resid)
{
	char *cp, *cp1;
	
	cp1 = cp = rstring(resid);
	while (*cp1 != 0) {
		if (*cp1 == '|') {
			*cp1 = 0;
		}
		cp1++;
	}
	return cp;
}				

//  MSGBOX  --  Format a message box with wsprintf and display

INT MsgBox(HWND hwndParent, UINT fuType, LPSTR pszFormat, ...)
{
    CHAR szOutput[MAX_PRINTF_OUTPUT];
    va_list ArgList;

    va_start(ArgList, pszFormat);
    wvsprintf(szOutput, pszFormat, ArgList);
    va_end(ArgList);

    return MessageBox(hwndParent, szOutput, pszAppName, fuType);
}

/*  WINPRINTF  --  Format a message with wsprintf and display
				   in a window with TextOut.  */

VOID WinPrintf(HDC hdc, INT row, INT col, LPSTR pszFormat, ...)
{
    CHAR szOutput[MAX_PRINTF_OUTPUT];
    INT cbOutput;
    va_list ArgList;

    va_start(ArgList, pszFormat);
    cbOutput = wvsprintf(szOutput, pszFormat, ArgList);
    va_end(ArgList);

    TextOut(hdc, col * tmAveCharWidth, row * tmHeight,
             szOutput, cbOutput);
}

//	DISPLAYHELPTOPICSTRING  --  Display help text for a given topic string

VOID displayHelpTopicString(LPCSTR topicStr)
{
#ifdef HTML_HELP
	char ht[256];

	if (!holped) {
		//	Initialise the HTML Help subsystem
		HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD) &HtmlHelpContext);
	}
	strcpy(ht, rstring(IDS_HELPFILE));
	strcat(ht, "::/html/");
	strcat(ht, topicStr);
	strcat(ht, ".htm");
	HtmlHelp(hwndMDIFrame, ht, HH_DISPLAY_TOPIC, 0);
#else
    WinHelp(hwndMDIFrame, rstring(IDS_HELPFILE), HELP_KEY, ((DWORD) (topicStr)));
#endif
	holped = TRUE;
}

//	DISPLAYHELPTOPIC  --  Display help text for a given topic from string resource ID

VOID displayHelpTopic(int topicResID)
{
	displayHelpTopicString(rstring(topicResID));
}

/*  SOCKERRTOSTRING  --  Return text corresponding to error codes
						 from WINSOCK.  */

LPSTR SockerrToString(SOCKERR serr)
{
	//	It would be too easy if these error codes were contiguous
    static SOCKERR socketErrorCodes[] = {
	    WSAENAMETOOLONG, WSANOTINITIALISED, WSASYSNOTREADY, WSAVERNOTSUPPORTED,
	    WSAESHUTDOWN, WSAEINTR, WSAHOST_NOT_FOUND, WSATRY_AGAIN, WSANO_RECOVERY,
	    WSANO_DATA, WSAEBADF, WSAEWOULDBLOCK, WSAEINPROGRESS, WSAEALREADY,
	    WSAEFAULT, WSAEDESTADDRREQ, WSAEMSGSIZE, WSAEPFNOSUPPORT, WSAENOTEMPTY,
	    WSAEPROCLIM, WSAEUSERS, WSAEDQUOT, WSAESTALE, WSAEINVAL, WSAEMFILE,
	    WSAEACCES, WSAELOOP, WSAEREMOTE, WSAENOTSOCK, WSAEADDRNOTAVAIL,
	    WSAEADDRINUSE, WSAEAFNOSUPPORT, WSAESOCKTNOSUPPORT, WSAEPROTONOSUPPORT,
	    WSAENOBUFS, WSAETIMEDOUT, WSAEISCONN, WSAENOTCONN, WSAENOPROTOOPT,
	    WSAECONNRESET, WSAECONNABORTED, WSAENETDOWN, WSAENETRESET, WSAECONNREFUSED,
	    WSAEHOSTDOWN, WSAEHOSTUNREACH, WSAEPROTOTYPE, WSAEOPNOTSUPP,
	    WSAENETUNREACH, WSAETOOMANYREFS
    };
    int i;

	for (i = 0; i < ELEMENTS(socketErrorCodes); i++) {
		if (serr == socketErrorCodes[i]) {  
			return rstring(IDS_SOCKET_ERRORS + i);
		}
	}
	return rstring(IDS_SOCKET_ERROR_UNKNOWN);	
}

//	RESETSOCKET  --  Perform a hard close on a socket

SOCKERR ResetSocket(SOCKET sock)
{
    LINGER linger;

    if (sock == INVALID_SOCKET) {
        return 0;
    }

    /*  Enable linger with a timeout of zero.  This will
		force the hard close when we call closesocket().

 		We ignore the error return from setsockopt.  If it
		fails, we'll just try to close the socket anyway. */

    linger.l_onoff  = TRUE;
    linger.l_linger = 0;

    setsockopt(sock, SOL_SOCKET, SO_LINGER, (CHAR *) &linger, sizeof(linger));

    return closesocket(sock);
}

//	CREATESOCKET  --  Create a new socket

SOCKERR CreateSocket(SOCKET *psock, INT type, ULONG address, PORT port)
{
    SOCKET  sNew;
    SOCKERR serr;

    //  Create the socket

    sNew = socket(PF_INET, type, 0);
    serr = (sNew == INVALID_SOCKET) ? WSAGetLastError(): 0;

    if ((serr == 0)
			&& (alwaysBindSocket || (port != 0))
        ) {
        SOCKADDR_IN sockAddr;

        //  Bind an address to the socket

        sockAddr.sin_family = AF_INET;
        sockAddr.sin_addr.s_addr = address;
        sockAddr.sin_port = port;

        if (bind(sNew, (SOCKADDR *) &sockAddr, sizeof(sockAddr)) != 0) {
            serr = WSAGetLastError();
        }
    }

    if (serr != 0) {
        ResetSocket(sNew);
        sNew = INVALID_SOCKET;
    }

    *psock = sNew;
    return serr;
}

//  REVSHORT  --  Reverse bytes in a short

void revshort(short *s)
{
	short s1 = *s;
	LPSTR ip = (LPSTR) &s1, op = (LPSTR) s;
	
	op[0] = ip[1];
	op[1] = ip[0];
}

//  REVLONG  --  Reverse bytes in a long

void revlong(long *l)
{
	long l1 = *l;
	LPSTR ip = (LPSTR) &l1, op = (LPSTR) l;
	
	op[0] = ip[3];
	op[1] = ip[2];
	op[2] = ip[1];
	op[3] = ip[0]; 
}

