/*++

Copyright (c) 1989-91  Microsoft Corporation

Module Name:

    namecmp.c

Abstract:

    Net name comparison functions:

        NetpwNameCompare
        CompareOemNames

Author:

    Richard L Firth (rfirth) 06-Jan-1992

Revision History:

--*/

#include "nticanon.h"

//
// prototypes
//

LONG
CompareOemNames(
    IN LPWSTR Name1,
    IN LPWSTR Name2,
    IN BOOL CaseInsensitive
    );

//
// data
//

static  TCHAR   szShareTrailChars[]     = TEXT(". ");

//
// routines
//


LONG
NetpwNameCompare(
    IN  LPTSTR  Name1,
    IN  LPTSTR  Name2,
    IN  DWORD   NameType,
    IN  DWORD   Flags
    )

/*++

Routine Description:

    Compares two LANMAN object names to see if they are the same. If the
    supplied names are not canonicalized this function will do the
    canonicalization of the names.

    This function does not do name validation.  It assumes that the two names
    have been validated separately.

    This function relies on the fact that the only difference between a
    canonicalized object name and an uncanonicalized object name is the case.

        (say what?...)

Arguments:

    Name1       - The first name to compare.

    Name2       - The second name to compare.

    NameType    - The type of the LANMAN object names.  Valid values are
                  specified by NAMETYPE_* manifests in ICANON.H.

    Flags       - Flags to determine operation.  Currently defined values are:

                    Xrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrc

                  where:

                    X = LM 2.x Compatibility

                    r = Reserved. MBZ.

                    c = should be set if both of the names have already been
                        canonicalized (using NetpwNameCanonicalize).

Return Value:

    0 if the two names match.

    Non-zero if they don't match, or if an invalid parameter is
    specified.

--*/

{
    LONG RetVal;
    NET_API_STATUS rc;
    TCHAR tName1[PATHLEN+1];
    TCHAR tName2[PATHLEN+1];

#ifdef CANONDBG
    DbgPrint("NetpwNameCompare\n");
#endif

    //
    // Parameter validation
    //

    if (Flags & INNC_FLAGS_RESERVED) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Determine which of the canonicalization functions to use.  We
    // use stricmp() if the names are not canonicalized and are not
    // case sensitive and strcmp() if the names are canonicalized or
    // if they are case sensitive.
    //

    switch (NameType) {

    //
    // Case insensitive name types
    //

    case NAMETYPE_USER:
    case NAMETYPE_GROUP:
    case NAMETYPE_COMPUTER:
    case NAMETYPE_EVENT:
    case NAMETYPE_DOMAIN:
    case NAMETYPE_SERVICE:
    case NAMETYPE_NET:
    case NAMETYPE_WORKGROUP:

        //
        // Use the case sensitive version if the names have been
        // canonicalized.
        //

        if (!(Flags & INNC_FLAGS_NAMES_CANONICALIZED)) {
            rc = NetpwNameCanonicalize(Name1,
                                       tName1,
                                       sizeof(tName1),
                                       NameType,
                                       Flags & LM2X_COMPATIBLE
                                       );
            if (rc != NERR_Success) {
                return rc;
            }
            rc = NetpwNameCanonicalize(Name2,
                                       tName2,
                                       sizeof(tName2),
                                       NameType,
                                       Flags & LM2X_COMPATIBLE
                                       );
            if (rc != NERR_Success) {
                return rc;
            }
        } else {
            LONG Name1Length, Name2Length;

            Name1Length = STRLEN(Name1);
            Name2Length = STRLEN(Name2);

            if ((Name1Length > PATHLEN) ||
                (Name2Length > PATHLEN)) {
                return ERROR_INVALID_PARAMETER;
            } else {
                STRCPY(tName1, Name1);
                STRCPY(tName2, Name2);
            }
        }
        if (Flags & (LM2X_COMPATIBLE)) {
            if (NameType == NAMETYPE_COMPUTER
            || NameType == NAMETYPE_DOMAIN
            || NameType == NAMETYPE_WORKGROUP) {
                return CompareOemNames(tName1, tName2, FALSE);
            } else {
                return STRCMP(tName1, tName2);
            }
        } else {
            if (NameType == NAMETYPE_COMPUTER
            || NameType == NAMETYPE_DOMAIN
            || NameType == NAMETYPE_WORKGROUP) {
                return CompareOemNames(tName1, tName2, TRUE);
            } else {
                return STRICMP(tName1, tName2);
            }
        }

    //
    // Case sensitive name types
    //

    case NAMETYPE_PASSWORD:
    case NAMETYPE_SHAREPASSWORD:
    case NAMETYPE_MESSAGE:
    case NAMETYPE_MESSAGEDEST:
        return STRCMP(Name1, Name2);

    //
    // Special handling for sharenames, since we mustn't consider
    // trailing dots and spaces in the comparison if the names haven't
    // been canonicalized.
    //

    case NAMETYPE_SHARE:
        if (Flags & INNC_FLAGS_NAMES_CANONICALIZED) {
            if (Flags & LM2X_COMPATIBLE) {
                return STRCMP(Name1, Name2);
            } else {
                return STRICMP(Name1, Name2);
            }
        } else {
            register DWORD RealLen1, RealLen2;

            RealLen1 = (DWORD)(strtail(Name1, szShareTrailChars) - Name1);
            RealLen2 = (DWORD)(strtail(Name2, szShareTrailChars) - Name2);

            //
            // If the lengths of the significant portions match, compare
            // these portions.  Otherwise, return non-zero based on this
            // length.
            //

            if (RealLen1 == RealLen2) {
                return STRNICMP(Name1, Name2, RealLen1);
            } else {
                return RealLen1 > RealLen2 ? 1 : -1;
            }
        }

    default:

        //
        // The caller specified an invalid name type
        //

        return ERROR_INVALID_PARAMETER;
    }
}


LONG
CompareOemNames(
    IN LPWSTR Name1,
    IN LPWSTR Name2,
    IN BOOL CaseInsensitive
    )

/*++

Routine Description:

    Converts 2 UNICODE name strings to corresponding OEM character set strings
    and then compares them

Arguments:

    Name1           -
    Name2           -
    CaseInsensitive - TRUE if compare without case

Return Value:

    LONG
        <0  Name1 less than Name2
         0  Names match
        >0  Name1 greater than Name2

--*/

{
    CHAR oemName1[PATHLEN + 1];
    ULONG oemByteLength1;
    ULONG name1Length;
    CHAR oemName2[PATHLEN + 1];
    ULONG oemByteLength2;
    ULONG name2Length;
    NTSTATUS ntStatus;

    name1Length = wcslen(Name1);
    name2Length = wcslen(Name2);

    //
    // only prepared to consider names within our upper length limit
    //

    if (name1Length >= sizeof(oemName1) || name2Length >= sizeof(oemName2)) {
        return -1;
    }

    //
    // convert UNICODE names to OEM
    //

    ntStatus = RtlUpcaseUnicodeToOemN(oemName1,
                                      sizeof(oemName1) - 1,
                                      &oemByteLength1,
                                      Name1,
                                      name1Length * sizeof(*Name1)
                                      );
    if (!NT_SUCCESS(ntStatus)) {
        return -1;
    } else {
        oemName1[oemByteLength1] = 0;
    }
    ntStatus = RtlUpcaseUnicodeToOemN(oemName2,
                                      sizeof(oemName2) - 1,
                                      &oemByteLength2,
                                      Name2,
                                      name2Length * sizeof(*Name2)
                                      );
    if (!NT_SUCCESS(ntStatus)) {
        return -1;
    } else {
        oemName2[oemByteLength2] = 0;
    }

    if (CaseInsensitive) {
        return _stricmp(oemName1, oemName2);
        }
    else {
        return strcmp(oemName1, oemName2);
        }
}