/*****************************************************************/
/**                  Microsoft LAN Manager                      **/
/**            Copyright(c) Microsoft Corp., 1990               **/
/*****************************************************************/


/*
    MiscAPIs.cxx
    Miscallaneous APIs


    FILE HISTORY:

    jonn        14-Jan-1991     Split from winprof.cxx
    jonn        17-Jan-1991     Split off lm21util.cxx, lm30spfc.cxx
    jonn        02-Feb-1991     Removed unused routines
    rustanl     12-Apr-1991     Added UI_UNCPathCompare and
                                UI_UNCPathValidate
    beng        17-May-1991     Correct lmui.hxx usage
    jonn        22-May-1991     Added MyNetUseAdd (was in winprof.cxx)
    rustanl     24-May-1991     Added AUTO_CURSOR to MyNetUseAdd
    terryk      31-Oct-1991     add mnet.h and change I_NetXXX to
                                I_MNetXXX
    Yi-HsinS    31-Dec-1991     Unicode work
    terryk  10-Oct-1993 deleted MyNetUseAdd

*/



#define INCL_WINDOWS
#define INCL_WINDOWS_GDI
#define INCL_DOSERRORS
#define INCL_NETERRORS
#define INCL_NETCONS
#define INCL_NETACCESS
#define INCL_NETSERVER
#define INCL_NETWKSTA
#define INCL_NETSERVICE
#define INCL_NETLIB
#define INCL_ICANON
#define INCL_NETUSE // for NetUseAdd
#define _WINNETWK_
#include <lmui.hxx>
#undef _WINNETWK_

extern "C"
{
    #include <mnet.h>
    #include <winnetwk.h>
    #include <npapi.h>
    #include <lmsname.h>
}

#include <uiassert.hxx>
#include <uitrace.hxx>
#include <string.hxx>
#include <lmowks.hxx>
#include <lmodom.hxx>
#include <lmodev.hxx> // for DEVICE object
#include <uibuffer.hxx>
#include <strchlit.hxx>  // for string and character literals
#include <lmsvc.hxx>
#include <miscapis.hxx>



/* Local prototypes */


/* functions */

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

    NAME:       CheckLMService

    SYNOPSIS:   Checks to make sure the LM Wksta service is willing to
                accept requests.

    RETURNS:    NERR_Success if the service is happy happy
                WN_NO_NETWORK if the service is stopped or stopping
                WN_FUNCTION_BUSY if the service is starting
                Other error if an error occurred getting the status

    NOTES:

    HISTORY:
        Johnl   09-Sep-1992     Created

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

APIERR CheckLMService( void )
{

    APIERR err = NERR_Success ;

    //
    // we almost always hit the wksta soon after this call & the wksta
    // is usually started. so this check will avoid paging in the service
    // controller. it just ends up paging in the wksta a bit earlier.
    // only if the call fails do we hit the service controller for the
    // actual status.
    //
    WKSTA_10 wksta_10 ;

    if ( (wksta_10.QueryError() == NERR_Success) &&
         (wksta_10.GetInfo() == NERR_Success) )
    {
        return NERR_Success ;
    }

    LM_SERVICE service( NULL, (const TCHAR *)SERVICE_WORKSTATION );
    if ( err = service.QueryError() )
    {
        return err ;
    }

    switch ( service.QueryStatus( &err ) )
    {
    case LM_SVC_STOPPED:
    case LM_SVC_STOPPING:
        if ( !err )
            err = WN_NO_NETWORK ;
        TRACEEOL("::CheckLMService - Returning WN_NO_NETWORK") ;
        break ;

    case LM_SVC_STARTING:
        if ( !err )
            err = WN_FUNCTION_BUSY ;
        TRACEEOL("::CheckLMService - Returning WN_FUNCTION_BUSY") ;
        break ;

    case LM_SVC_STATUS_UNKNOWN:
    case LM_SVC_STARTED:
    case LM_SVC_PAUSED:
    case LM_SVC_PAUSING:
    case LM_SVC_CONTINUING:
    default:
        /* Return unadultered error code
         */
        break ;
    }

    return err ;
}


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

    NAME:       ParseRemoteName

    SYNOPSIS:   Canonicalizes a remote resource name and determines
        its type

    ARGUMENTS:
        RemoteName - Remote resource name to be parsed
        CanonName - Buffer for canonicalized name, assumed to be
            MAX_PATH characters long
        CanonNameSize - Size, in bytes, of output buffer
        PathStart - Set to the offset, in characters, of the start
            of the "\share" portion (in the REMOTENAMETYPE_SHARE case)
            or the "\path" portion (in the REMOTENAMETYPE_PATH case)
            of the name within CanonName.  Not set in other cases.

    RETURNS:
        If nlsRemote is like    Then returns
        --------------------    ------------
        workgroup               REMOTENAMETYPE_WORKGROUP
        \\server                REMOTENAMETYPE_SERVER
        \\server\share          REMOTENAMETYPE_SHARE
        \\server\share\path     REMOTENAMETYPE_PATH
        (other)                 REMOTENAMETYPE_INVALID

    NOTES:

    HISTORY:
      AnirudhS  21-Apr-1995 Ported from Win95 sources - used netlib
        functions rather than ad hoc parsing, introduced comments

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

REMOTENAMETYPE ParseRemoteName(
    IN  LPWSTR  RemoteName,
    OUT LPWSTR  CanonName,
    IN  DWORD   CanonNameSize,
    OUT PULONG  PathStart
    )
{
    //
    // Determine the path type
    //
    DWORD PathType = 0;
    NET_API_STATUS Status = I_NetPathType(NULL, RemoteName, &PathType, 0);

    if (Status != NERR_Success)
    {
        return REMOTENAMETYPE_INVALID;
    }

    //
    // I_NetPathType doesn't give us quite as fine a classification of
    // path types as we need, so we still need to do a little more parsing
    //
    switch (PathType)
    {
    case ITYPE_PATH_RELND:
        //
        // A driveless relative path
        // A valid workgroup or domain name would be classified as
        // such, but it still needs to be validated as a workgroup name
        //
        Status = I_NetNameCanonicalize(
                            NULL,               // ServerName
                            RemoteName,         // Name
                            CanonName,          // Outbuf
                            CanonNameSize,      // OutbufLen
                            NAMETYPE_WORKGROUP, // NameType
                            0                   // Flags
                            );

        if (Status == NERR_Success)
        {
            return REMOTENAMETYPE_WORKGROUP;
        }
        else
        {
            return REMOTENAMETYPE_INVALID;
        }

    case ITYPE_UNC_COMPNAME:
        //
        // A UNC computername, "\\server"
        //
        {
            //
            // HACK: I_NetPathCanonicalize likes "\\server\share" but not
            // "\\server", so append a dummy share name to canonicalize.
            // We assume that the CanonName buffer will still be big
            // enough (which it will, in the calls made from this file).
            //
            if (wcslen(RemoteName) + 3 > NNLEN)
            {
                return REMOTENAMETYPE_INVALID;
            }
            WCHAR wszDummy[NNLEN];
            wcscpy(wszDummy, RemoteName);
            wcscat(wszDummy, L"\\a");

            UIASSERT(CanonNameSize >= sizeof(wszDummy));
            PathType = ITYPE_UNC;
            Status = I_NetPathCanonicalize(
                                    NULL,           // ServerName
                                    wszDummy,       // PathName
                                    CanonName,      // Outbuf
                                    CanonNameSize,  // OutbufLen
                                    NULL,           // Prefix
                                    &PathType,      // PathType
                                    0               // Flags
                                    );
        }

        if (Status != NERR_Success)
        {
            return REMOTENAMETYPE_INVALID;
        }

        CanonName[ wcslen(CanonName) - 2 ] = 0;

        return REMOTENAMETYPE_SERVER;

    case ITYPE_UNC:
        //
        // A UNC path, either "\\server\share" or "\\server\share\path" -
        // canonicalize and determine which one
        //
        Status = I_NetPathCanonicalize(
                                    NULL,           // ServerName
                                    RemoteName,     // PathName
                                    CanonName,      // Outbuf
                                    CanonNameSize,  // OutbufLen
                                    NULL,           // Prefix
                                    &PathType,      // PathType
                                    0               // Flags
                                    );
        if (Status != NERR_Success)
        {
            return REMOTENAMETYPE_INVALID;
        }

        {
            WCHAR * pSlash = wcschr(CanonName+2, PATH_SEPARATOR);
            UIASSERT(pSlash);
            *PathStart = (ULONG)(pSlash - CanonName);

            // Look for a fourth slash
            pSlash = wcschr(pSlash+1, PATH_SEPARATOR);
            if (pSlash)
            {
                *PathStart = (ULONG)(pSlash - CanonName);
                return REMOTENAMETYPE_PATH;
            }
            else
            {
                return REMOTENAMETYPE_SHARE;
            }
        }

    default:
        return REMOTENAMETYPE_INVALID;
    }
}