/*************************************************************************
*
*  NT.C
*
*  NT NetWare routines
*
*  Copyright (c) 1995 Microsoft Corporation
*
*  $Log:   N:\NT\PRIVATE\NW4\NWSCRIPT\VCS\NT.C  $
*  
*     Rev 1.4   22 Dec 1995 14:25:12   terryt
*  Add Microsoft headers
*  
*     Rev 1.3   28 Nov 1995 17:13:28   terryt
*  Cleanup resource file
*  
*     Rev 1.2   22 Nov 1995 15:43:44   terryt
*  Use proper NetWare user name call
*  
*     Rev 1.1   20 Nov 1995 16:10:00   terryt
*  Close open NDS handles
*  
*     Rev 1.0   15 Nov 1995 18:07:18   terryt
*  Initial revision.
*  
*     Rev 1.2   25 Aug 1995 16:23:02   terryt
*  Capture support
*  
*     Rev 1.1   23 May 1995 19:37:02   terryt
*  Spruce up source
*  
*     Rev 1.0   15 May 1995 19:10:40   terryt
*  Initial revision.
*  
*************************************************************************/
#include <common.h>

#include <nwapi.h>
#include <npapi.h>

#include "ntnw.h"
/*
 * Name of NetWare provider
 */
TCHAR NW_PROVIDER[60];
unsigned char NW_PROVIDERA[60];

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

        NTPrintExtendedError

Routine Description:

        Print any extended errors from WNet routines

Arguments:
        None

Return Value:
        None

 *******************************************************************/
void
NTPrintExtendedError( void )
{
    DWORD ExError;
    wchar_t provider[32];
    wchar_t description[1024];

    if ( !WNetGetLastErrorW( &ExError, description, 1024, provider, 32 ) )
        wprintf(L"%s\n", description);
}


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

        NTInitProvider

Routine Description:

        Retrieve provider name and save old paths

Arguments:
        None

Return Value:
        None

 *******************************************************************/
void
NTInitProvider( void )
{
    HKEY hKey;
    DWORD dwType, dwSize;
    LONG Status;
    BOOL ret = FALSE;

    dwSize = sizeof(NW_PROVIDER);
    if ((Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_PROVIDER, 0, KEY_READ, &hKey)) == ERROR_SUCCESS) {
        (void) RegQueryValueEx(hKey, REGISTRY_PROVIDERNAME, NULL, &dwType, (LPBYTE) NW_PROVIDER, &dwSize);
        WideTosz( NW_PROVIDERA, NW_PROVIDER, sizeof(NW_PROVIDERA) );
    }

    RegCloseKey(hKey);

    GetOldPaths();
}

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

        DeleteDriveBase

Routine Description:

        Disconnect drive from network

Arguments:

        DriveNumber - number of drive 1-26

Return Value:
        0 - success
        else NetWare error

 *******************************************************************/
unsigned int
DeleteDriveBase( unsigned short DriveNumber)
{
    static char drivename[] = "A:";
    unsigned int dwRes;

    drivename[0] = 'A' + DriveNumber - 1;

    dwRes = WNetCancelConnection2A( drivename, 0, TRUE );

    if ( dwRes != NO_ERROR )
        dwRes = GetLastError();

    if ( dwRes == ERROR_EXTENDED_ERROR )
        NTPrintExtendedError();

    return dwRes;
}

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

        DetachFromFileServer

Routine Description:

        Break connection from a file server

Arguments:

        ConnectionId - Connection handle

Return Value:
        0 = success
        else NT error

 *******************************************************************/
unsigned int
DetachFromFileServer( unsigned int ConnectionId )
{
    return ( NWDetachFromFileServer( (NWCONN_HANDLE)ConnectionId ) );
}


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

        NTLoginToFileServer

Routine Description:

        Login to a file server given a user name and password.

        If a NULL password is passed in, the default password should
        be tried if no password failed.

Arguments:

        pszServerName - Server name
        pszUserName   - User name
        pszPassword   - Password

Return Value:
        0 = success
        else NetWare error

 *******************************************************************/
unsigned int
NTLoginToFileServer(
    char          *pszServerName,
    char          *pszUserName,
    char          *pszPassword
    )
{
    NETRESOURCEA       NetResource;
    DWORD              dwRes;

    //
    // validate parameters
    //
    if (!pszServerName || !pszUserName || !pszPassword) {
        DisplayMessage(IDR_ERROR_DURING, "NTLoginToFileServer");
        return 0xffffffff ;
    }

    NetResource.dwScope      = 0 ;
    NetResource.dwUsage      = 0 ;
    NetResource.dwType       = RESOURCETYPE_ANY;
    NetResource.lpLocalName  = NULL;
    NetResource.lpRemoteName = pszServerName;
    NetResource.lpComment    = NULL;
    NetResource.lpProvider   = NW_PROVIDERA ;

    //
    // make the connection 
    //
    dwRes=WNetAddConnection2A ( &NetResource, 
                                pszPassword, 
                                pszUserName,
                                0 );
    if ( dwRes != NO_ERROR )
       dwRes = GetLastError();

    //
    // Try default password if no password was specified
    //
    // The error numbers aren't (or weren't) reliable (ERROR_INVALID_PASSWORD)
    //
    if ( ( dwRes != NO_ERROR ) && ( pszPassword[0] == '\0' ) ) {
        dwRes=WNetAddConnection2A ( &NetResource, 
                                    NULL, 
                                    pszUserName,
                                        0 );
        if ( dwRes != NO_ERROR )
           dwRes = GetLastError();
    }

    return( dwRes );
}

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

        GetFileServerName

Routine Description:

        Return the server name associated with the connection ID

Arguments:

        ConnectionId - Connection ID to a server
        pServerName  - Returned server name

Return Value:
        0 - success
        else NT error

 *******************************************************************/
unsigned int
GetFileServerName(
    unsigned int      ConnectionId,
    char *            pServerName
    )
{
    unsigned int Result;
    VERSION_INFO VerInfo;

    *pServerName = '\0';

    Result = NWGetFileServerVersionInfo( (NWCONN_HANDLE) ConnectionId,
                                         &VerInfo );
    if ( !Result )
    {
        strcpy( pServerName, VerInfo.szName );
    }

    return Result;
}

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

        SetDriveBase

Routine Description:

        Connect a drive to a NetWare volume

Arguments:

        DriveNumber      - number of drive 1-26
        ServerName       - server name
        DirHandle        - not used
        pDirPath         - Volume:\Path

Return Value:
        0 = success
        else NetWare error

 *******************************************************************/
unsigned int
SetDriveBase(
    unsigned short   DriveNumber,
    unsigned char   *ServerName,
    unsigned int     DirHandle,
    unsigned char   *pDirPath
    )
{
    unsigned int Result = 0;
    static char driveName[] = "A:" ;

    /*
     * DirHandle is never used
     */

    driveName[0]= 'A' + DriveNumber - 1;

    if ( ( ServerName[0] == '\0' ) && fNDS ) {

        /*
         * Assume its an NDS volume name, if that fails, then
         * try a default file server volume.
         */
        Result = NTSetDriveBase( driveName, NDSTREE, pDirPath );

        if ( !Result )
            return Result;

        Result = NTSetDriveBase( driveName, PREFERRED_SERVER, pDirPath );

        return Result;
    }

    Result = NTSetDriveBase( driveName, ServerName, pDirPath );

    return Result;
}


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

        NTSetDriveBase

Routine Description:

        Connect a local name to a NetWare volume and path

Arguments:

        pszLocalName   -  local name to connect
        pszServerName  -  name of file server
        pszDirPath     -  Volume:\Path

Return Value:
        0 = success
        else NetWare error

 *******************************************************************/
unsigned int
NTSetDriveBase( unsigned char * pszLocalName,
                unsigned char * pszServerName,
                unsigned char * pszDirPath )
{
    NETRESOURCEA       NetResource;
    DWORD              dwRes, dwSize;
    unsigned char * pszRemoteName = NULL; 
    char * p;

    //
    // validate parameters
    //
    if (!pszLocalName || !pszServerName || !pszDirPath) {
        DisplayMessage(IDR_ERROR_DURING, "NTSetDriveBase");
        return 0xffffffff ;
    }

    //
    // allocate memory for string
    //
    dwSize = strlen(pszDirPath) + strlen(pszServerName) + 5 ;
    if (!(pszRemoteName = (unsigned char *)LocalAlloc(
                                       LPTR, 
                                       dwSize)))
    {
        DisplayMessage(IDR_NOT_ENOUGH_MEMORY);
        dwRes = 0xffffffff;
        goto ExitPoint ; 
    }

    //
    // The requester understands 
    // server\volume:dir
    // but not
    // server\volume:\dir
    //
    // So just convert it to UNC
    //

    strcpy( pszRemoteName, "\\\\" );
    strcat( pszRemoteName, pszServerName );
    strcat( pszRemoteName, "\\" );
    strcat( pszRemoteName, pszDirPath );

    p = strchr( pszRemoteName, ':' );
    if ( !p ) {
        DisplayMessage(IDR_NO_VOLUME);
        dwRes = 0xffffffff;
        goto ExitPoint ; 
    }
    *p++ = '\\';

    if ( *p == '\\' ) {
       /* Don't want a double backslash */
       *p = '\0';
       p = strchr( pszDirPath, ':' );
       p++;
       p++;
       strcat( pszRemoteName, p );
    }

    //
    // strip off trailing backslash
    //
    if (pszRemoteName[strlen(pszRemoteName)-1] == '\\')
        pszRemoteName[strlen(pszRemoteName)-1] = '\0';

    NetResource.dwScope      = 0 ;
    NetResource.dwUsage      = 0 ;
    NetResource.dwType       = RESOURCETYPE_DISK;
    NetResource.lpLocalName  = pszLocalName;
    NetResource.lpRemoteName = pszRemoteName;
    NetResource.lpComment    = NULL;
    NetResource.lpProvider   = NW_PROVIDERA ;

    //
    // make the connection 
    //
    dwRes=WNetAddConnection2A ( &NetResource, NULL, NULL, 0 );

    if ( dwRes != NO_ERROR )
        dwRes = GetLastError();

ExitPoint: 

    if (pszRemoteName)
        (void) LocalFree((HLOCAL) pszRemoteName) ;

    return( dwRes );
}


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

        Is40Server

Routine Description:

        Returns TRUE if 4X server

Arguments:

        ConnectionHandle - Connection Handle

Return Value:
        TRUE = 4X server
        FALSE = pre-4X server

 *******************************************************************/
unsigned int
Is40Server(
    unsigned int       ConnectionHandle
    )
{
    NTSTATUS NtStatus ;
    VERSION_INFO VerInfo;
    unsigned int Version;

    NtStatus = NWGetFileServerVersionInfo( (NWCONN_HANDLE)ConnectionHandle,
                                            &VerInfo );

    if (!NT_SUCCESS(NtStatus)) 
       FALSE;

    Version = VerInfo.Version * 1000 + VerInfo.SubVersion * 10;

    if ( Version >= 4000 ) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}

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

        CleanupExit

Routine Description:

        Does any cleanup and exits

Arguments:

        ExitCode - exit code for exit()

Return Value:
        does not return

 *******************************************************************/
void 
CleanupExit ( int ExitCode )
{
    if ( fNDS )
       NDSCleanup();

    exit( ExitCode );
}

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

        NTGetNWUserName

Routine Description:

        Get NetWare user name

Arguments:

        TreeBuffer  IN - wide string for server or tree
	UserName    OUT - user name 
	Length      IN - length of user name

Return Value:
        error message

 *******************************************************************/
int
NTGetNWUserName( PWCHAR TreeBuffer, PWCHAR UserName, int Length ) 
{

    NTSTATUS ntstatus;
    IO_STATUS_BLOCK IoStatusBlock;
    OBJECT_ATTRIBUTES ObjectAttributes;
    ACCESS_MASK DesiredAccess = SYNCHRONIZE | FILE_LIST_DIRECTORY;
    HANDLE hRdr;

    WCHAR DevicePreamble[] = L"\\Device\\Nwrdr\\";
    UINT PreambleLength = 14;

    WCHAR NameStr[64];
    UNICODE_STRING OpenName;
    UINT i;

    UNICODE_STRING NdsTree;

    //
    // Copy over the preamble.
    //

    OpenName.MaximumLength = sizeof( NameStr );

    for ( i = 0; i < PreambleLength ; i++ )
        NameStr[i] = DevicePreamble[i];

    RtlInitUnicodeString( &NdsTree, TreeBuffer );

    //
    // Copy the server or tree name.
    //

    for ( i = 0 ; i < ( NdsTree.Length / sizeof( WCHAR ) ) ; i++ ) {
        NameStr[i + PreambleLength] = NdsTree.Buffer[i];
    }

    OpenName.Length = ( i * sizeof( WCHAR ) ) +
		       ( PreambleLength * sizeof( WCHAR ) );
    OpenName.Buffer = NameStr;

    //
    // Set up the object attributes.
    //

    InitializeObjectAttributes( &ObjectAttributes,
                                &OpenName,
				OBJ_CASE_INSENSITIVE,
				NULL,
				NULL );

    ntstatus = NtOpenFile( &hRdr,
                           DesiredAccess,
			   &ObjectAttributes,
			   &IoStatusBlock,
			   FILE_SHARE_VALID_FLAGS,
			   FILE_SYNCHRONOUS_IO_NONALERT );

    if ( !NT_SUCCESS(ntstatus) )
        return ntstatus;

    ntstatus = NtFsControlFile( hRdr,
                                NULL,
				NULL,
				NULL,
				&IoStatusBlock,
				FSCTL_NWR_GET_USERNAME,
				(PVOID) TreeBuffer,
				NdsTree.Length,
				(PVOID) UserName,
				Length );

   UserName[(USHORT)IoStatusBlock.Information/2] = 0;

   NtClose( hRdr );
   return ntstatus;

}