/**********************************************************************/
/**                       Microsoft Windows NT                       **/
/**                Copyright(c) Microsoft Corp., 1991                **/
/**********************************************************************/

/*
    user.c
    This module implements the "user" command of the W3 Server
    debugger extension DLL.

    The "user" command dumps the info pertaining to a specific user.
    There is one parameter to this command.  If this parameter is
    positive, it is assumed to be the address of a USER_DATA structure
    for a specific user.  If the parameter is negative, its absolute
    value is assumed to be a user ID.  If no parameter is given, info
    for all connected users is dumped.


    FILE HISTORY:
        KeithMo     13-Aug-1992 Created.

*/


#include "w3dbg.h"


//
//  Private prototypes.
//

VOID DumpUserInfo( HANDLE      hCurrentProcess,
                   USER_DATA * puser );

CHAR * InterpretState( USER_STATE state );

CHAR * InterpretXferType( XFER_TYPE xferType );

CHAR * InterpretXferMode( XFER_MODE xferMode );

VOID InterpretFlags( DWORD dwFlags );



/*******************************************************************

    NAME:       user

    SYNOPSIS:   Displays the info for a specific user.

    ENTRY:      hCurrentProcess         - Handle to the current process.

                hCurrentThread          - Handle to the current thread.

                dwCurrentPc             - The current program counter
                                          (EIP for x86, FIR for MIPS).

                lpExtensionApis         - Points to a structure containing
                                          pointers to the debugger functions
                                          that the command may invoke.

                lpArgumentString        - Points to any arguments passed
                                          to the command.

    NOTES:      The argument string must contain either the address of
                a USER_DATA structure (if positive) or a user ID (if
                negative).

    HISTORY:
        KeithMo     13-Aug-1992 Created.

********************************************************************/
VOID user( HANDLE hCurrentProcess,
           HANDLE hCurrentThread,
           DWORD  dwCurrentPc,
           LPVOID lpExtensionApis,
           LPSTR  lpArgumentString )
{
    LONG         lParam;
    USER_DATA    user;

    //
    //  Grab the debugger entrypoints.
    //

    GrabDebugApis( lpExtensionApis );

    //
    //  Evaluate the parameter (if present).
    //

    if( ( lpArgumentString == NULL ) || ( *lpArgumentString == '\0' ) )
    {
        lParam = 0;
    }
    else
    {
        lParam = (LONG)DebugEval( lpArgumentString );
    }

    //
    //  Interpret the parameter.
    //

    if( lParam > 0 )
    {
        //
        //  User specified an address.  Dump the user info
        //  at that address.
        //

        ReadProcessMemory( hCurrentProcess,
                           (LPVOID)lParam,
                           (LPVOID)&user,
                           sizeof(user),
                           (LPDWORD)NULL );

        DumpUserInfo( hCurrentProcess, &user );
    }
    else
    {
        //
        //  User specified either nothing (0) or a user ID (< 0).
        //

        LIST_ENTRY   list;
        LIST_ENTRY * plist;
        LIST_ENTRY * plistHead;

        lParam = -lParam;

        plistHead = (LIST_ENTRY *)DebugEval( "listUserData" );

        ReadProcessMemory( hCurrentProcess,
                           (LPVOID)plistHead,
                           (LPVOID)&list,
                           sizeof(list),
                           (LPDWORD)NULL );

        plist = list.Flink;

        while( plist != plistHead )
        {
            ReadProcessMemory( hCurrentProcess,
                               (LPVOID)CONTAINING_RECORD( plist,
                                                          USER_DATA,
                                                          link ),
                               (LPVOID)&user,
                               sizeof(user),
                               (LPDWORD)NULL );

            if( ( lParam == 0 ) || ( user.idUser == (DWORD)lParam ) )
            {
                DumpUserInfo( hCurrentProcess, &user );

                if( lParam != 0 )
                {
                    break;
                }
            }

            plist = user.link.Flink;

            //
            //  Check for CTRL-C, to let the user bag-out early.
            //

            if( DebugCheckCtrlC() )
            {
                break;
            }
        }

        if( ( lParam != 0 ) && ( plist == plistHead ) )
        {
            DebugPrint( "user ID %ld not found\n", lParam );
        }
    }

}   // user


VOID DumpUserInfo( HANDLE      hCurrentProcess,
                   USER_DATA * puser )
{
    char szDir[MAX_PATH];
    int  i;

    DebugPrint( "user @ %08lX:\n", puser );
    DebugPrint( "    link.Flink = %08lX\n", puser->link.Flink );
    DebugPrint( "    link.Blink = %08lX\n", puser->link.Blink );
    DebugPrint( "    dwFlags    = %08lX\n", puser->dwFlags );
    InterpretFlags( puser->dwFlags );
    DebugPrint( "    sControl   = %d\n",    puser->sControl );
    DebugPrint( "    sData      = %d\n",    puser->sData );
    DebugPrint( "    hToken     = %08lX\n", puser->hToken );
    DebugPrint( "    state      = %s\n",    InterpretState( puser->state ) );
    DebugPrint( "    idUser     = %lu\n",   puser->idUser );
    DebugPrint( "    tConnect   = %08lX\n", puser->tConnect );
    DebugPrint( "    tAccess    = %08lX\n", puser->tAccess );
    DebugPrint( "    xferType   = %s\n",    InterpretXferType( puser->xferType ) );
    DebugPrint( "    xferMode   = %s\n",    InterpretXferMode( puser->xferMode ) );
    DebugPrint( "    inetLocal  = %s\n",    inet_ntoa( puser->inetLocal ) );
    DebugPrint( "    inetHost   = %s\n",    inet_ntoa( puser->inetHost ) );
    DebugPrint( "    inetData   = %s\n",    inet_ntoa( puser->inetData ) );
    DebugPrint( "    portData   = %u\n",    puser->portData );
    DebugPrint( "    hDir       = %08lX\n", puser->hDir );
    DebugPrint( "    pIoBuffer  = %08lX\n", puser->pIoBuffer );
    DebugPrint( "    pszRename  = %s\n",    puser->pszRename );
    for( i = 0 ; i < 26 ; i++ )
    {
        if( puser->apszDirs[i] != NULL )
        {
            ReadProcessMemory( hCurrentProcess,
                               puser->apszDirs[i],
                               szDir,
                               sizeof(szDir),
                               (LPDWORD)NULL );

            DebugPrint( "    dir %c:     = %s\n", 'A'+i, szDir );
        }
    }
    DebugPrint( "    szDir      = %s\n",    puser->szDir );
    DebugPrint( "    szUser     = %s\n",    puser->szUser );
    DebugPrint( "    idThread   = %lu\n",   puser->idThread );

    DebugPrint( "\n" );

}   // DumpUserInfo


CHAR * InterpretState( USER_STATE state )
{
    CHAR * pszResult = "unknown";

    switch( state )
    {
    case Embryonic :
        pszResult = "Embryonic";
        break;

    case WaitingForUser :
        pszResult = "WaitingForUser";
        break;

    case WaitingForPass :
        pszResult = "WaitingForPass";
        break;

    case LoggedOn :
        pszResult = "LoggedOn";
        break;

    case Disconnected :
        pszResult = "Disconnected";
        break;

    default :
        break;
    }

    return pszResult;

}   // InterpretState


CHAR * InterpretXferType( XFER_TYPE xferType )
{
    CHAR * pszResult = "unknown";

    switch( xferType )
    {
    case AsciiType :
        pszResult = "ASCII";
        break;

    case BinaryType :
        pszResult = "BINARY";
        break;

    default :
        break;
    }

    return pszResult;

}   // InterpretXferType


CHAR * InterpretXferMode( XFER_MODE xferMode )
{
    CHAR * pszResult = "unknown";

    switch( xferMode )
    {
    case StreamMode :
        pszResult = "STREAM";
        break;

    case BlockMode :
        pszResult = "BLOCK";
        break;

    default :
        break;
    }

    return pszResult;

}   // InterpretXferMode


typedef struct FLAG_MAP
{
    DWORD   flag;
    CHAR  * pszName;

} FLAG_MAP;

FLAG_MAP flag_map[] =
    {
        { UF_MSDOS_DIR_OUTPUT, "UF_MSDOS_DIR_OUTPUT" },
        { UF_ANNOTATE_DIRS,    "UF_ANNOTATE_DIRS"    },
        { UF_READ_ACCESS,      "UF_READ_ACCESS"      },
        { UF_WRITE_ACCESS,     "UF_WRITE_ACCESS"     },
        { UF_OOB_ABORT,        "UF_OOB_ABORT"        },
        { UF_RENAME,           "UF_RENAME"           },
        { UF_PASSIVE,          "UF_PASSIVE"          },
        { UF_ANONYMOUS,        "UF_ANONYMOUS"        },
        { UF_TRANSFER,         "UF_TRANSFER"         },
        { UF_OOB_DATA,         "UF_OOB_DATA"         }
    };
#define NUM_FLAG_MAP (sizeof(flag_map) / sizeof(flag_map[0]))


VOID InterpretFlags( DWORD dwFlags )
{
    INT        i;
    FLAG_MAP * pmap = flag_map;

    for( i = 0 ; i < NUM_FLAG_MAP ; i++ )
    {
        if( dwFlags & pmap->flag )
        {
            DebugPrint( "                 %s\n", pmap->pszName );
            dwFlags &= ~pmap->flag;
        }

        pmap++;
    }

    if( dwFlags != 0 )
    {
        DebugPrint( "                 Remaining flags = %08lX\n", dwFlags );
    }

}   // InterpretFlags