/****************************** Module Header ******************************\
* Module Name: utils.c
*
* Purpose: Conatains all the utility routines
*
* Created: 1990
*
* Copyright (c) 1990, 1991  Microsoft Corporation
*
* History:
*   Raor, Srinik (../../1990)    Designed and coded
*   curts created portable version for WIN16/32
*
\***************************************************************************/

#include <windows.h>
#include "cmacs.h"
#include <shellapi.h>

#include "ole.h"
#include "dde.h"
#include "srvr.h"

#define KB_64   65536

extern ATOM    aTrue;
extern ATOM    aFalse;
#ifdef WIN16
extern BOOL    bWLO;
extern BOOL    bWin30;
#endif

extern ATOM    aStdCreateFromTemplate;
extern ATOM    aStdCreate;
extern ATOM    aStdOpen;
extern ATOM    aStdEdit;
extern ATOM    aStdShowItem;
extern ATOM    aStdClose;
extern ATOM    aStdExit;
extern ATOM    aStdDoVerbItem;

extern BOOL (FAR PASCAL *lpfnIsTask) (HANDLE);

// MapToHexStr: Converts  WORD to hex string.
void INTERNAL MapToHexStr (
    LPSTR       lpbuf,
    HANDLE      hdata
){
    int     i;
    char    ch;

    *lpbuf++ = '@';
    for ( i = sizeof(HANDLE)*2 - 1; i >= 0; i--) {

	ch = (char) ((((DWORD_PTR)hdata) >> (i * 4)) & 0x0000000f);
	if(ch > '9')
	    ch += 'A' - 10;
	else
	    ch += '0';

	*lpbuf++ = ch;
    }

    *lpbuf++ = '\0';

}


void INTERNAL UtilMemCpy (
    LPSTR   lpdst,
    LPCSTR  lpsrc,
    DWORD   dwCount
){
    UINT HUGE_T * hpdst;
    UINT HUGE_T * hpsrc;
    UINT FAR  * lpwDst;
    UINT FAR  * lpwSrc;
    DWORD       words;
    DWORD       bytes;

    bytes = dwCount %  MAPVALUE(2,4);
    words = dwCount >> MAPVALUE(1,2); //* we compare DWORDS
				      //* in the 32 bit version
#ifdef WIN16
    if (dwCount <= KB_64) {
	lpwDst = (WORD FAR *) lpdst;
	lpwSrc = (WORD FAR *) lpsrc;
	
	while (words--)
	    *lpwDst++ = *lpwSrc++;

	if (bytes)
	    * (char FAR *) lpwDst = * (char FAR *) lpwSrc;
    }
    else
#else
    UNREFERENCED_PARAMETER(lpwDst);
    UNREFERENCED_PARAMETER(lpwSrc);
#endif
    {
	hpdst = (UINT HUGE_T *) lpdst;
	hpsrc = (UINT HUGE_T *) lpsrc;

	for(;words--;)
	    *hpdst++ = *hpsrc++;
			
	lpdst = (LPSTR) hpdst;
	lpsrc = (LPSTR) hpsrc;

	for(;bytes--;)
	    *lpdst++ = *lpsrc++;
    }
}


//DuplicateData: Duplicates a given Global data handle.
HANDLE  INTERNAL    DuplicateData (
    HANDLE  hdata
){
    LPSTR   lpsrc = NULL;
    LPSTR   lpdst = NULL;
    HANDLE  hdup  = NULL;
    DWORD   size;
    BOOL    err   = TRUE;

    if(!(lpsrc =  GlobalLock (hdata)))
	return NULL;

    DEBUG_OUT (lpsrc, 0)

    hdup = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, (size = (DWORD)GlobalSize(hdata)));

    if(!(lpdst =  GlobalLock (hdup)))
	goto errRtn;;

    err = FALSE;
    UtilMemCpy (lpdst, lpsrc, size);

errRtn:
    if(lpsrc)
	GlobalUnlock (hdata);

    if(lpdst)
	GlobalUnlock (hdup);

    if (err && hdup)
	GlobalFree (hdup);

    return hdup;
}


//ScanBoolArg: scans the argument which is not included in
//the quotes. These args could be only TRUE or FALSE for
//the time being. !!!The scanning routines should be
//merged and it should be generalized.

LPSTR   INTERNAL    ScanBoolArg (
    LPSTR   lpstr,
    BOOL    FAR *lpflag
){
    LPSTR   lpbool;
    ATOM    aShow;
    char    ch;

    lpbool = lpstr;

    // !!! These routines does not take care of quoted quotes.

    while((ch = *lpstr) && (!(ch == ')' || ch == ',')))
	lpstr++;

    if (ch == '\0')
       return NULL;

    *lpstr++ = '\0';       // terminate the arg by null

    // if terminated by paren, then check for end of command
    // syntax.

    // Check for the end of the command string.
    if (ch == ')') {
	if (*lpstr++ != ']')
	    return NULL;

	if (*lpstr != '\0')
	    return NULL;             //finally should be terminated by null.

    }

    aShow = GlobalFindAtom (lpbool);
    if (aShow == aTrue)
	*lpflag = TRUE;

    else {
	if (aShow ==aFalse)
	    *lpflag = FALSE;
	else
	    return NULL;;
    }
    return lpstr;
}




//ScannumArg: Checks for the syntax of num arg in Execute and if
//the arg is syntactically correct, returns the ptr to the
//beginning of the next arg and also, returns the number
//Does not take care of the last num arg in the list.

LPSTR INTERNAL ScanNumArg (
    LPSTR   lpstr,
    LPINT   lpnum
){
    WORD    val = 0;
    char    ch;

    while((ch = *lpstr++) && (ch != ',')) {
	if (ch < '0' || ch >'9')
	    return NULL;
	val += val * 10 + (ch - '0');

    }

    if(!ch)
       return NULL;

    *lpnum = val;
    return lpstr;
}




//ScanArg: Checks for the syntax of arg in Execute and if
//the arg is syntactically correct, returns the ptr to the
//beginning of the next arg or to the end of the excute string.

LPSTR INTERNAL ScanArg (
    LPSTR   lpstr
){


    // !!! These routines does not take care of quoted quotes.

    // first char should be quote.

    if (*(lpstr-1) != '\"')
	return NULL;

    while(*lpstr && *lpstr != '\"')
	lpstr++;

    if(*lpstr == '\0')
       return NULL;

    *lpstr++ = '\0';       // terminate the arg by null

    if(!(*lpstr == ',' || *lpstr == ')'))
	return NULL;


    if(*lpstr++ == ','){

	if(*lpstr == '\"')
	    return ++lpstr;
	// If it is not quote, leave the ptr on the first char
	return lpstr;
    }

    // terminated by paren
    // already skiped right paren

    // Check for the end of the command string.
    if (*lpstr++ != ']')
	return NULL;

    if(*lpstr != '\0')
	return NULL;             //finally should be terminated by null.

    return lpstr;
}

// ScanCommand: scanns the command string for the syntax
// correctness. If syntactically correct, returns the ptr
// to the first arg or to the end of the string.

WORD INTERNAL  ScanCommand (
    LPSTR       lpstr,
    UINT        wType,
    LPSTR FAR * lplpnextcmd,
    ATOM FAR *  lpAtom
){
    // !!! These routines does not take care of quoted quotes.
    // and not taking care of blanks arround the operators

    // !!! We are not allowing blanks after operators.
    // Should be allright! since this is arestricted syntax.

    char    ch;
    LPSTR   lptemp = lpstr;


    while(*lpstr && (!(*lpstr == '(' || *lpstr == ']')))
	lpstr++;

    if(*lpstr == '\0')
       return 0;

    ch = *lpstr;
    *lpstr++ = '\0';       // set the end of command

    *lpAtom = GlobalFindAtom (lptemp);

    if (!IsOleCommand (*lpAtom, wType))
	return NON_OLE_COMMAND;

    if (ch == '(') {
	ch = *lpstr++;

	if (ch == ')') {
	     if (*lpstr++ != ']')
		return 0;
	}
	else {
	    if (ch != '\"')
		return 0;
	}
	
	*lplpnextcmd = lpstr;
	return OLE_COMMAND;
    }

    // terminated by ']'

    if (*(*lplpnextcmd = lpstr)) // if no nul termination, then it is error.
	return 0;

    return OLE_COMMAND;
}


//MakeDataAtom: Creates a data atom from the item string
//and the item data otions.

ATOM INTERNAL MakeDataAtom (
    ATOM    aItem,
    int     options
){
    char    buf[MAX_STR];

    if (options == OLE_CHANGED)
	return DuplicateAtom (aItem);

    if (!aItem)
	buf[0] = '\0';
    else
	GlobalGetAtomName (aItem, (LPSTR)buf, MAX_STR);

    if (options == OLE_CLOSED)
	lstrcat ((LPSTR)buf, (LPSTR) "/Close");
    else {
	if (options == OLE_SAVED)
	   lstrcat ((LPSTR)buf, (LPSTR) "/Save");
    }

    if (buf[0])
	return GlobalAddAtom ((LPSTR)buf);
    else
	return (ATOM)0;
}

//DuplicateAtom: Duplicates an atom
ATOM INTERNAL DuplicateAtom (
    ATOM    atom
){
    char buf[MAX_STR];

    Puts ("DuplicateAtom");

    if (!atom)
	return (ATOM)0;

    GlobalGetAtomName (atom, buf, MAX_STR);
    return GlobalAddAtom (buf);
}

// MakeGlobal: makes global out of strings.
// works only for << 64k

HANDLE  INTERNAL MakeGlobal (
    LPCSTR  lpstr
){

    int     len = 0;
    HANDLE  hdata  = NULL;
    LPSTR   lpdata = NULL;

    len = lstrlen (lpstr) + 1;

    hdata = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, len);
    if (hdata == NULL || (lpdata = (LPSTR) GlobalLock (hdata)) == NULL)
	goto errRtn;


    UtilMemCpy (lpdata, lpstr, (DWORD)len);
    GlobalUnlock (hdata);
    return hdata;

errRtn:

    if (lpdata)
	GlobalUnlock (hdata);


    if (hdata)
	GlobalFree (hdata);

     return NULL;

}



BOOL INTERNAL CheckServer (
    LPSRVR  lpsrvr
){
    if (!CheckPointer(lpsrvr, WRITE_ACCESS))
	return FALSE;

    if ((lpsrvr->sig[0] == 'S') && (lpsrvr->sig[1] == 'R'))
	return TRUE;

    return FALSE;
}


BOOL INTERNAL CheckServerDoc (
    LPDOC   lpdoc
){
    if (!CheckPointer(lpdoc, WRITE_ACCESS))
	return FALSE;

    if ((lpdoc->sig[0] == 'S') && (lpdoc->sig[1] == 'D'))
	return TRUE;

    return FALSE;
}


BOOL INTERNAL PostMessageToClientWithBlock (
    HWND    hWnd,
    UINT    wMsg,
    WPARAM  wParam,
    LPARAM  lParam
){

    if (!IsWindowValid (hWnd)){
	ASSERT(FALSE, "Client's window is missing");
	return FALSE;
    }

    if (IsBlockQueueEmpty ((HWND)wParam) && PostMessage (hWnd, wMsg, wParam, lParam))
	return TRUE;

    BlockPostMsg (hWnd, wMsg, wParam, lParam);
    return TRUE;
}



BOOL INTERNAL PostMessageToClient (
    HWND    hWnd,
    UINT    wMsg,
    WPARAM  wParam,
    LPARAM  lParam
){
    if (!IsWindowValid (hWnd)){
	ASSERT(FALSE, "Client's window is missing");
	return FALSE;
    }


    if (IsBlockQueueEmpty ((HWND)wParam) && PostMessage (hWnd, wMsg, wParam, lParam))
	return TRUE;

    BlockPostMsg (hWnd, wMsg, wParam, lParam);
    return TRUE;
}


BOOL    INTERNAL IsWindowValid (
    HWND    hwnd
){

#define TASK_OFFSET 0x00FA

    LPSTR   lptask;
    HANDLE  htask;

    if (!IsWindow (hwnd))
	return FALSE;

#ifdef WIN32
   UNREFERENCED_PARAMETER(lptask);
   UNREFERENCED_PARAMETER(htask);
   return TRUE;//HACK
#endif

#ifdef WIN16
    if (bWLO)
	return TRUE;

    // now get the task handle and find out it is valid.
    htask  = GetWindowTask (hwnd);

    if (bWin30 || !lpfnIsTask) {
	lptask = (LPSTR)(MAKELONG (TASK_OFFSET, htask));

	if (!CheckPointer(lptask, READ_ACCESS))
	    return FALSE;

	// now check for the signature bytes of task block in kernel
	if (*lptask++ == 'T' && *lptask == 'D')
	    return TRUE;
    }
    else {
	// From win31 onwards the API IsTask() can be used for task validation
	if ((*lpfnIsTask)(htask))
	    return TRUE;
    }
#endif

    return FALSE;
}



BOOL INTERNAL UtilQueryProtocol (
    ATOM    aClass,
    LPSTR   lpprotocol
){
    HKEY    hKey;
    char    key[MAX_STR];
    char    class[MAX_STR];

    if (!aClass)
	return FALSE;

    if (!GlobalGetAtomName (aClass, class, MAX_STR))
	return FALSE;

    lstrcpy (key, class);
    lstrcat (key, "\\protocol\\");
    lstrcat (key, lpprotocol);
    lstrcat (key, "\\server");

    if (RegOpenKey (HKEY_CLASSES_ROOT, key, &hKey))
	return FALSE;

    RegCloseKey (hKey);
    return TRUE;
}


BOOL INTERNAL IsOleCommand (
    ATOM    aCmd,
    UINT    wType
){
    if (wType == WT_SRVR) {
	if ((aCmd == aStdCreateFromTemplate)
		|| (aCmd == aStdCreate)
		|| (aCmd == aStdOpen)
		|| (aCmd == aStdEdit)
		|| (aCmd == aStdShowItem)
		|| (aCmd == aStdClose)
		|| (aCmd == aStdExit))
	    return TRUE;
    }
    else {
	if ((aCmd == aStdClose)
		|| (aCmd == aStdDoVerbItem)
		|| (aCmd == aStdShowItem))
	    return TRUE;
    }

    return FALSE;
}