// ----------------------------------------------------------------------------
// debug.c
//
// Microsoft At Work Fax Debugging Utilities
//
// Copyright (C) 1993 Microsoft Corporation
// ----------------------------------------------------------------------------
/* Revision History:
 *
 *      When            Who                                     What
 *      --------        ------------------  ---------------------------------------
 *      3.17.94         MAPI                            Original source from MAPI mapidbg.c
 *      3.17.94         Yoram Yaacovi           Modifications to overcome compobj.h problems
 *      3.7.94          Yoram Yaacovi           Update to MAPI build 154
 *      12.1.94         Yoram Yaacovi           Added DebugLog()
 *
 ***********************************************************************/

#include <windows.h>
#include <stdio.h>
#include <time.h>
//#include "faxcfg.h"
#include "mapi.h"
#include "mapidbg.h"
#include "mapidefs.h"
#include "mapicode.h"
#ifdef DEBUG

/*
 *
 *      From current\src\mapi\inc\_memcpy.h
 *
 *      MemCopy()
 *
 *      A much safer version of memcpy that checks the value of the byte
 *      count before calling the memcpy() function.  This macro is only built
 *      into the 16 bit non-debug builds.
 */

#ifndef __MEMCPY_H_
#define __MEMCPY_H_

#define MemCopy(_dst,_src,_cb)  memcpy(_dst,_src,(size_t)(_cb))

#endif



#if defined(WIN16) || defined(WIN32)
static BOOL fTraceEnabled       = -1;
static BOOL fLogTraceEnabled    = -1;
static BOOL fAssertLeaks        = -1;

static TCHAR szKeyTraceEnabled[]    = TEXT("DebugTrace");
static TCHAR szKeyLogTraceEnabled[] = TEXT("DebugTraceLog");
static TCHAR szKeyDebugTrap[]       = TEXT("DebugTrap");
static TCHAR szKeyExtendedDebug[]   = TEXT("ExtendedDebug");
static TCHAR szKeyUseVirtual[]      = TEXT("VirtualMemory");
static TCHAR szKeyAssertLeaks[]     = TEXT("AssertLeaks");
static TCHAR szKeyCheckOften[]      = TEXT("CheckHeapOften");
static TCHAR szSectionDebug[]       = TEXT("General");
static TCHAR szDebugIni[]           = TEXT("MAWFDBG.INI");
#endif


// ExtendedDebug --------------------------------------------------------------
BOOL ExtendedDebug(void)
{
        return (GetPrivateProfileInt(szSectionDebug, szKeyExtendedDebug,
                0, szDebugIni));
}

// DebugTrap --------------------------------------------------------------
void DebugTrap(void)
{
        if (GetPrivateProfileInt(szSectionDebug, szKeyDebugTrap,
                0, szDebugIni))

                DebugBreak();
}

// DebugLog --------------------------------------------------------------

void DebugLog(LPSTR szString)
{
        FILE *logfile;

        // open a log file for appending. create if does not exist
        if ((logfile = fopen ("c:\\uilog.txt", "a+")) != NULL)
        {
                fwrite (szString, 1, strlen(szString), logfile);
                fclose(logfile);
        }
}


// DebugOutputFn --------------------------------------------------------------

void DebugOutputFn(char *psz)
{
#if defined(_MAC)

        OutputDebugString(psz);

#else

        char *  pszBeg;
        char *  pszEnd;
        char    szBuf[3];

#if defined(WIN16) || defined(WIN32)
        if (fTraceEnabled == -1)
        {
                fTraceEnabled = GetPrivateProfileInt(szSectionDebug, szKeyTraceEnabled,
                        0, szDebugIni);
        }

        if (!fTraceEnabled)
                return;

        if (fLogTraceEnabled == -1)
        {
                fLogTraceEnabled =
                        GetPrivateProfileInt(szSectionDebug, szKeyLogTraceEnabled, 0, szDebugIni);
        }

#endif

        for (pszBeg = psz; pszBeg && *pszBeg; pszBeg = pszEnd) {
                pszEnd = strchr(pszBeg, '\n');

                if (pszEnd) {
                        MemCopy(szBuf, pszEnd, 3);
                        if (pszEnd > pszBeg && *(pszEnd - 1) != '\r')
                                strcpy(pszEnd, "\r\n");
                        else
                                *(pszEnd + 1) = 0;
                }

                if (fLogTraceEnabled)
                        DebugLog(pszBeg);
                else
                        OutputDebugStringA(pszBeg);

                if (pszEnd) {
                        MemCopy(pszEnd, szBuf, 3);
                        pszEnd += 1;
                }
        }
#endif
}

// DebugTrapFn ----------------------------------------------------------------

#if defined(WIN32) && defined(THREAD_MSG_BOX)

typedef struct {
        char *          sz1;
        char *          sz2;
        UINT            rgf;
        int                     iResult;
} MBContext;

DWORD WINAPI MessageBoxFnThreadMain(MBContext *pmbc)
{
        pmbc->iResult = MessageBoxA(NULL, pmbc->sz1, pmbc->sz2,
                pmbc->rgf | MB_SETFOREGROUND);
        return(0);
}

int MessageBoxFn(char *sz1, char *sz2, UINT rgf)
{
        HANDLE          hThread;
        DWORD           dwThreadId;
        MBContext       mbc;

        mbc.sz1         = sz1;
        mbc.sz2         = sz2;
        mbc.rgf         = rgf;
        mbc.iResult = IDRETRY;

        hThread = CreateThread(NULL, 0,
                (PTHREAD_START_ROUTINE)MessageBoxFnThreadMain, &mbc, 0, &dwThreadId);

        if (hThread != NULL) {
                WaitForSingleObject(hThread, INFINITE);
                CloseHandle(hThread);
        }

        return(mbc.iResult);
}
#else
#define MessageBoxFn(sz1, sz2, rgf)             MessageBoxA(NULL, sz1, sz2, rgf)
#endif

int __cdecl DebugTrapFn(int fFatal, char *pszFile, int iLine, char *pszFormat, ...)
{
        char    sz[512];
        va_list vl;

        #if defined(WIN16) || defined(WIN32)
        int             id;
        #endif

        strcpy(sz, "++++ MAWF Debug Trap (");
        _strdate(sz + strlen(sz));
        strcat(sz, " ");
        _strtime(sz + strlen(sz));
        strcat(sz, ")\n");
        DebugOutputFn(sz);

        va_start(vl, pszFormat);
        wvsprintfA(sz, pszFormat, vl);
        va_end(vl);

        wsprintfA(sz + strlen(sz), "\n[File %s, Line %d]\n\n", pszFile, iLine);

        DebugOutputFn(sz);

        #if defined(DOS)
        _asm { int 3 }
        #endif

        #if defined(WIN16) || defined(WIN32)
        // Hold down control key to prevent MessageBox
        if ( GetAsyncKeyState(VK_CONTROL) >= 0 )
        {
                id = MessageBoxFn(sz, "Microsoft At Work Fax Debug Trap",
                                MB_ABORTRETRYIGNORE | MB_ICONHAND | MB_TASKMODAL |
                                (fFatal ? MB_DEFBUTTON1 : MB_DEFBUTTON3));

                if (id == IDABORT)
                        *((LPBYTE)NULL) = 0;
                else if (id == IDRETRY)
                        DebugBreak();
        }
        #endif

        return(0);
}

// ExtendedDebugTraceFn ---------------------------------------------------------------

int __cdecl ExtendedDebugTraceFn(char *pszFormat, ...)
{
        char    sz[512];
        int             fAutoLF = 0;
        va_list vl;

        if (ExtendedDebug())
        {
                if (*pszFormat == '~') {
                        pszFormat += 1;
                        fAutoLF = 1;
                }

                va_start(vl, pszFormat);
                wvsprintfA(sz, pszFormat, vl);
                va_end(vl);

                if (fAutoLF)
                        strcat(sz, "\n");

                DebugOutputFn(sz);
        }

        return(0);
}

// DebugTraceFn ---------------------------------------------------------------

int __cdecl DebugTraceFn(char *pszFormat, ...)
{
        char    sz[512];
        char    sz1[512];
        int             fAutoLF = 0;
        va_list vl;
        HINSTANCE hInst=NULL; // this really needs to be a parameter

        if (*pszFormat == '~') {
                pszFormat += 1;
                fAutoLF = 1;
        }

        va_start(vl, pszFormat);
        wvsprintfA(sz, pszFormat, vl);
        va_end(vl);

        if (fAutoLF)
                strcat(sz, "\n");

        strcpy(sz1, sz);

        DebugOutputFn(sz1);

        return(0);
}


// SCODE & PropTag decoding ---------------------------------------------------

typedef struct
{
        char *                  psz;
        unsigned long   ulPropTag;
} PT;

typedef struct
{
        char *  psz;
        SCODE   sc;
} SC;

#define Pt(_ptag)       {#_ptag, _ptag}
#define Sc(_sc)         {#_sc, _sc}

#if !defined(DOS)
static PT rgpt[] = {
/*
 * Property types
 */
    Pt(PT_UNSPECIFIED),
    Pt(PT_NULL),
    Pt(PT_I2),
    Pt(PT_LONG),
    Pt(PT_R4),
    Pt(PT_DOUBLE),
    Pt(PT_CURRENCY),
    Pt(PT_APPTIME),
    Pt(PT_ERROR),
    Pt(PT_BOOLEAN),
    Pt(PT_OBJECT),
    Pt(PT_I8),
    Pt(PT_STRING8),
    Pt(PT_UNICODE),
    Pt(PT_SYSTIME),
    Pt(PT_CLSID),
    Pt(PT_BINARY),
    Pt(PT_TSTRING),
    Pt(PT_MV_I2),
    Pt(PT_MV_LONG),
    Pt(PT_MV_R4),
    Pt(PT_MV_DOUBLE),
    Pt(PT_MV_CURRENCY),
    Pt(PT_MV_APPTIME),
    Pt(PT_MV_SYSTIME),
    Pt(PT_MV_STRING8),
    Pt(PT_MV_BINARY),
    Pt(PT_MV_UNICODE),
    Pt(PT_MV_CLSID),
    Pt(PT_MV_I8)
};

#define cpt (sizeof(rgpt) / sizeof(PT))

static SC rgsc[] = {

/* FACILITY_NULL error codes from OLE */

                                        Sc(S_OK),
                                        Sc(S_FALSE),

                                        Sc(E_UNEXPECTED),
                                        Sc(E_NOTIMPL),
                                        Sc(E_OUTOFMEMORY),
                                        Sc(E_INVALIDARG),
                                        Sc(E_NOINTERFACE),
                                        Sc(E_POINTER),
                                        Sc(E_HANDLE),
                                        Sc(E_ABORT),
                                        Sc(E_FAIL),
                                        Sc(E_ACCESSDENIED),

/* General errors (used by more than one MAPI object) */

                                        Sc(MAPI_E_NO_SUPPORT),
                                        Sc(MAPI_E_BAD_CHARWIDTH),
                                        Sc(MAPI_E_STRING_TOO_LONG),
                                        Sc(MAPI_E_UNKNOWN_FLAGS),
                                        Sc(MAPI_E_INVALID_ENTRYID),
                                        Sc(MAPI_E_INVALID_OBJECT),
                                        Sc(MAPI_E_OBJECT_CHANGED),
                                        Sc(MAPI_E_OBJECT_DELETED),
                                        Sc(MAPI_E_BUSY),
                                        Sc(MAPI_E_NOT_ENOUGH_DISK),
                                        Sc(MAPI_E_NOT_ENOUGH_RESOURCES),
                                        Sc(MAPI_E_NOT_FOUND),
                                        Sc(MAPI_E_VERSION),
                                        Sc(MAPI_E_LOGON_FAILED),
                                        Sc(MAPI_E_SESSION_LIMIT),
                                        Sc(MAPI_E_USER_CANCEL),
                                        Sc(MAPI_E_UNABLE_TO_ABORT),
                                        Sc(MAPI_E_NETWORK_ERROR),
                                        Sc(MAPI_E_DISK_ERROR),
                                        Sc(MAPI_E_TOO_COMPLEX),
                                        Sc(MAPI_E_BAD_COLUMN),
                                        Sc(MAPI_E_EXTENDED_ERROR),
                                        Sc(MAPI_E_COMPUTED),

/* MAPI base function and status object specific errors and warnings */

                                        Sc(MAPI_E_END_OF_SESSION),
                                        Sc(MAPI_E_UNKNOWN_ENTRYID),
                                        Sc(MAPI_E_MISSING_REQUIRED_COLUMN),

/* Property specific errors and warnings */

                                        Sc(MAPI_E_BAD_VALUE),
                                        Sc(MAPI_E_INVALID_TYPE),
                                        Sc(MAPI_E_TYPE_NO_SUPPORT),
                                        Sc(MAPI_E_UNEXPECTED_TYPE),
                                        Sc(MAPI_E_TOO_BIG),

                                        Sc(MAPI_W_ERRORS_RETURNED),

/* Table specific errors and warnings */

                                        Sc(MAPI_E_UNABLE_TO_COMPLETE),
                                        Sc(MAPI_E_TABLE_EMPTY),
                                        Sc(MAPI_E_TABLE_TOO_BIG),
                                        Sc(MAPI_E_INVALID_BOOKMARK),

                                        Sc(MAPI_W_POSITION_CHANGED),
                                        Sc(MAPI_W_APPROX_COUNT),

/* Transport specific errors and warnings */

                                        Sc(MAPI_E_WAIT),
                                        Sc(MAPI_E_CANCEL),
                                        Sc(MAPI_E_NOT_ME),

                                        Sc(MAPI_W_CANCEL_MESSAGE),

/* Message Store, Folder, and Message specific errors and warnings */

                                        Sc(MAPI_E_CORRUPT_STORE),
                                        Sc(MAPI_E_NOT_IN_QUEUE),
                                        Sc(MAPI_E_NO_SUPPRESS),
                                        Sc(MAPI_E_COLLISION),
                                        Sc(MAPI_E_NOT_INITIALIZED),
                                        Sc(MAPI_E_NON_STANDARD),
                                        Sc(MAPI_E_NO_RECIPIENTS),
                                        Sc(MAPI_E_SUBMITTED),
                    Sc(MAPI_E_HAS_FOLDERS),
                    Sc(MAPI_E_HAS_MESSAGES),
                    Sc(MAPI_E_FOLDER_CYCLE),

/* Address Book specific errors and warnings */

                                        Sc(MAPI_E_AMBIGUOUS_RECIP)

                                        };

#define csc (sizeof(rgsc) / sizeof(SC))
#endif

char * __cdecl
SzDecodeScodeFn(SCODE sc)
{
        static char rgch[64];

        #if !defined(DOS)
        int isc;
        for (isc = 0; isc < csc; ++isc)
                if (sc == rgsc[isc].sc)
                        return rgsc[isc].psz;
        #endif

        wsprintfA (rgch, "%08lX", sc);
        return rgch;
}


#else   // no DEBUG

typedef long SCODE;
// need to define empty functions for DEF file resolution
BOOL ExtendedDebug(void)
{
        return FALSE;
}
void DebugTrap(void)
{
}
int __cdecl DebugTrapFn(int fFatal, char *pszFile, int iLine, char *pszFormat, ...)
{
        return 0;
}
int __cdecl DebugTraceFn(char *pszFormat, ...)
{
        return 0;
}
int __cdecl ExtendedDebugTraceFn(char *pszFormat, ...)
{
        return 0;
}
char * __cdecl SzDecodeScodeFn(SCODE sc)
{
        return NULL;
}

#endif