/****************************** 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
*
\***************************************************************************/

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

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


#ifndef HUGE
#define HUGE    huge
#endif

#define KB_64   65536

extern ATOM    aTrue;
extern ATOM    aFalse;
extern BOOL    bWLO;
extern BOOL    bWin30;

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 (lpbuf, hdata)
LPSTR       lpbuf;
HANDLE      hdata;
{
    int     i;
    char    ch;

    *lpbuf++ = '@';
    for ( i = 3; i >= 0; i--) {

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

        *lpbuf++ = ch;
    }

    *lpbuf++ = NULL;

}


void INTERNAL UtilMemCpy (lpdst, lpsrc, dwCount)
LPSTR   lpdst;
LPSTR   lpsrc;
DWORD   dwCount;
{
    WORD HUGE * hpdst;
    WORD HUGE * hpsrc;
    WORD FAR  * lpwDst;
    WORD FAR  * lpwSrc;
    DWORD       words;
    DWORD       bytes;
    
    bytes = dwCount %  2;
    words = dwCount >> 1;           //* we should compare DWORDS
                                    //* in the 32 bit version 
    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 {
        hpdst = (WORD HUGE *) lpdst;
        hpsrc = (WORD HUGE *) lpsrc;
    
        while (words--) 
            *hpdst++ = *hpsrc++;

        if (bytes) 
            *(char HUGE *) hpdst = * (char HUGE *) hpsrc;
    }
}


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

    hdup = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, (size = 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, lpflag)
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 == ',')))
    {								//[J1]
#if	defined(FE_SB)						//[J1]
	lpstr = AnsiNext( lpstr );				//[J1]
#else								//[J1]
        lpstr++;
#endif								//[J1]
    }								//[J1]

    if(ch == NULL)
       return NULL;

    *lpstr++ = NULL;       // 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 != NULL)
            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, lpnum)
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   lpstr;
{


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

    // first char should be quote.

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

    while(*lpstr && *lpstr != '\"')
    {								//[J1]
#if	defined(FE_SB)						//[J1]
	lpstr = AnsiNext( lpstr );				//[J1]
#else								//[J1]
        lpstr++;
#endif								//[J1]
    }								//[J1]

    if(*lpstr == NULL)
       return NULL;

    *lpstr++ = NULL;       // 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 != NULL)
        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, wType, lplpnextcmd, lpAtom)
LPSTR       lpstr;
WORD        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 == ']')))
    {								//[J1]
#if	defined(FE_SB)						//[J1]
	lpstr = AnsiNext( lpstr );				//[J1]
#else								//[J1]
        lpstr++;
#endif								//[J1]
    }								//[J1]

    if(*lpstr == NULL)
       return NULL;

    ch = *lpstr;
    *lpstr++ = NULL;       // set the end of command

    *lpAtom = GlobalFindAtom (lptemp);

    if (!IsOleCommand (*lpAtom, wType))
        return NON_OLE_COMMAND;
    
    if (ch == '(') {

#if	defined(FE_SB)						//[J1]
	ch = *lpstr;						//[J1]
	lpstr = AnsiNext( lpstr );				//[J1]
#else								//[J1]
        ch = *lpstr++;
#endif								//[J1]

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

    // terminated by ']'

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

    return OLE_COMMAND;
}


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

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

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

    if (!aItem)
        buf[0] = NULL;
    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 NULL;
}

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

    Puts ("DuplicateAtom");

    if (!atom)
        return NULL;
    
    GlobalGetAtomName (atom, buf, MAX_STR);
    return GlobalAddAtom (buf);
}

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

HANDLE  INTERNAL MakeGlobal (lpstr)
LPSTR   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  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   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, wMsg, wParam, lParam)
HWND    hWnd;
WORD    wMsg;
WORD    wParam;
DWORD   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, wMsg, wParam, lParam)
HWND    hWnd;
WORD    wMsg;
WORD    wParam;
DWORD   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    hwnd;
{

#define TASK_OFFSET 0x00FA

    LPSTR   lptask;
    HANDLE  htask;

    if (!IsWindow (hwnd))
        return FALSE;

    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;
    }
    
    return FALSE;
}



BOOL INTERNAL UtilQueryProtocol (aClass, lpprotocol)
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 (aCmd, wType)
ATOM    aCmd;
WORD    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;
}