/******************************************************************************
Copyright (c) Microsoft Corporation

Module Name:

    Disconnect.cpp

Abstract:

    Disconnects one or more open files

Author:
  
     Akhil Gokhale (akhil.gokhale@wipro.com) 1-Nov-2000
  
Revision History:
  
       Akhil Gokhale (akhil.gokhale@wipro.com) 1-Nov-2000 : Created It.

******************************************************************************/
//include headers
#include "pch.h"
#include "Disconnect.h"

/*-----------------------------------------------------------------------------
Routine Description:

Disconnects one or more openfiles
     
Arguments: 

    [in]    pszServer      - remote server name
    [in]    pszID          - Open file ids
    [in]    pszAccessedby  - Name of  user name who access the file
    [in]    pszOpenmode    - accessed mode 
    [in]    pszOpenFile    - Open file name  

Returned Value:

            - TRUE for success exit
            - FALSE for failure exit
-----------------------------------------------------------------------------*/
BOOL
DisconnectOpenFile( PTCHAR pszServer,
                    PTCHAR pszID, 
                    PTCHAR pszAccessedby, 
                    PTCHAR pszOpenmode, 
                    PTCHAR pszOpenFile )
{
    // local variables to this function
    BOOL bResult = FALSE;// Stores fuctions return value status.

    DWORD dwEntriesRead = 0;// Receives the count of elements actually 
                            // enumerated by "NetFileEnum" function
    DWORD dwTotalEntries = 0;//Receives the total number of entries that could 
                             //have been enumerated from the current 
                             //resume position by "NetFileEnum" function
    DWORD dwResumeHandle = 0;//Contains a resume handle which is used to 
                             //continue an existing file search. 
                             //The handle should be zero on the first call and 
                             //left unchanged for subsequent calls. 
                             //If resume_handle is NULL, 
                             //then no resume handle is stored. This variable
                             // used in calling "NetFileEnum" function.
    LPFILE_INFO_3 pFileInfo3_1 = NULL; //LPFILE_INFO_3  structure contains the 
                                       //identification number and other 
                                       //pertinent information about files, 
                                       //devices, and pipes.

    DWORD dwError = 0;//Contains return value for "NetFileEnum" function
    NET_API_STATUS nStatus = 0;// Stores return value for NetFileClose functin

    TCHAR szResult[(MAX_RES_STRING*2) + 1] = NULL_STRING;
       
    AFP_FILE_INFO* pFileInfo = NULL;
    DWORD hEnumHandle = 0;
    HRESULT hr = S_OK;
    NET_API_STATUS retval = NERR_Success;
    AFP_SERVER_HANDLE ulSFMServerConnection = 0;
    TCHAR   szDllPath[MAX_PATH+1] = NULL_STRING;// buffer for Windows directory
    
    
    HMODULE hModule = 0;          // To store retval for LoadLibrary
  
      
    DWORD         dwConnectionId            = 0;

    typedef DWORD (*AFPCONNECTIONCLOSEPROC) (AFP_SERVER_HANDLE,DWORD); // Function pointer
    typedef DWORD (*CONNECTPROC) (LPWSTR,PAFP_SERVER_HANDLE);// Function pointer
    typedef  DWORD (*FILEENUMPROC)(AFP_SERVER_HANDLE,LPBYTE*,DWORD,LPDWORD,LPDWORD,LPDWORD);

    AFPCONNECTIONCLOSEPROC AfpAdminFileClose = NULL;  
    CONNECTPROC  AfpAdminConnect = NULL; 
    FILEENUMPROC AfpAdminFileEnum = NULL;// Function Pointer
    

    //varibles to store whether the given credentials are matching with the 
    //got credentials.

    BOOL    bId = FALSE;
    BOOL    bAccessedBy = FALSE;
    BOOL    bOpenmode   = FALSE;
    BOOL    bOpenfile   = FALSE;
    BOOL    bIfatleast  = FALSE;
    do
    {
        // Get the block of files
        dwError = NetFileEnum( pszServer, 
                               NULL, 
                               NULL, 
                               3, 
                               (LPBYTE *)&pFileInfo3_1, 
                               MAX_PREFERRED_LENGTH,
                               &dwEntriesRead,
                               &dwTotalEntries, 
                               (PDWORD_PTR)&dwResumeHandle );
        if(dwError == ERROR_ACCESS_DENIED)
        {
            SetLastError(ERROR_ACCESS_DENIED);
            DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
            ShowLastError(stderr);
            return FALSE;

        }
        if( dwError == NERR_Success || dwError == ERROR_MORE_DATA )
        {
            for ( DWORD dwFile = 0; 
                  dwFile < dwEntriesRead;
                  dwFile++, pFileInfo3_1++ )
            {
                //Check whether the got open file is file or names pipe.
                // If named pipe leave it. As this utility do not 
                // disconnect Named pipe
                if ( IsNamedPipePath(pFileInfo3_1->fi3_pathname ) )
                {
                    continue;
                }
                else//Not a named pipe. is a file
                {   
                    bId = IsSpecifiedID(pszID,pFileInfo3_1->fi3_id); 
                    bAccessedBy = IsSpecifiedAccessedBy(pszAccessedby, 
                                                   pFileInfo3_1->fi3_username);
                    bOpenmode = IsSpecifiedOpenmode(pszOpenmode,
                                                pFileInfo3_1->fi3_permissions);
                    bOpenfile = IsSpecifiedOpenfile(pszOpenFile,
                                                pFileInfo3_1->fi3_pathname);
                    // Proceed for dicconecting the open file only if 
                    // all previous fuction returns true. This insures that
                    // user preference is taken care.

                    if( bId && 
                        bAccessedBy && 
                        bOpenmode && 
                        bOpenfile)
                    {
                        bIfatleast = TRUE;
                        memset( szResult, 0, (((MAX_RES_STRING*2) + 1) *
                                sizeof( TCHAR )) );
                        //The NetFileClose function forces a resource to close.
                        nStatus = NetFileClose(pszServer, 
                                               pFileInfo3_1->fi3_id);
                        if(nStatus == NERR_Success)
                        {
                            // Create the output message string as File
                            // is successfully deleted.
                            // Output string will be :
                            // SUCCESS: Connection to openfile "filename"
                            // has been terminated.
                            bResult = TRUE;
                            FORMAT_STRING(szResult,DISCONNECTED_SUCCESSFULLY,pFileInfo3_1->fi3_pathname);
                            DISPLAY_MESSAGE(stdout, szResult);
                        }
                        else
                        {
                           // As unable to disconnect the openfile make  
                           // output message as 
                           // ERROR: could not dissconnect "filename".
                            bResult = FALSE;
                            FORMAT_STRING(szResult,DISCONNECT_UNSUCCESSFUL,pFileInfo3_1->fi3_pathname);
                            DISPLAY_MESSAGE(stderr, szResult);
                        }
                        // Display output result as previously constructed.
                    }//If bId...
                }//else part of is named pipe
             }
        }
   } while ( dwError == ERROR_MORE_DATA );
    // Free the block
    if( pFileInfo3_1 !=NULL)
    {
    NetApiBufferFree( pFileInfo3_1 ); 
    pFileInfo3_1 = NULL;
    }


   // Now disconnect files for MAC OS

    do
    {
        // DLL required is stored always in \windows\system32 directory....        
        // so get windows directory first.
        if(GetSystemDirectory(szDllPath, MAX_PATH)!= 0)
        {
            lstrcat(szDllPath,MAC_DLL_FILE_NAME); 
            hModule = ::LoadLibrary (szDllPath);

            if(hModule==NULL)
            {
                DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
                ShowLastError(stderr); // Shows the error string set by API function.
                return FALSE;

            }
        }
        else
        {
                DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
                ShowLastError(stderr); // Shows the error string set by API function.
                return FALSE;
        }
       
        AfpAdminConnect = (CONNECTPROC)::GetProcAddress (hModule,"AfpAdminConnect");
        AfpAdminFileClose = (AFPCONNECTIONCLOSEPROC)::GetProcAddress (hModule,"AfpAdminFileClose");
        AfpAdminFileEnum = (FILEENUMPROC)::GetProcAddress (hModule,"AfpAdminFileEnum");

        // Check if  all function pointer successfully taken from DLL
        // if not show error message and exit
        if((AfpAdminFileClose== NULL)||
           (AfpAdminConnect  == NULL)||
           (AfpAdminFileEnum == NULL))

        {
            DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
            ShowLastError(stderr); // Shows the error string set by API function.
            FREE_LIBRARY(hModule);
            return FALSE;
        }
        
        // Connection ID is requered for AfpAdminFileEnum function so 
        // connect to server to get connect id...
        DWORD retval_connect =  AfpAdminConnect(const_cast<LPWSTR>(pszServer),
                                &ulSFMServerConnection );
        if(retval_connect!=0)
        {
            DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
            ShowLastError(stderr); // Shows the error string set by API function.
            FREE_LIBRARY(hModule);
             return FALSE;
        }

      dwError =     AfpAdminFileEnum( ulSFMServerConnection,
                                      (PBYTE*)&pFileInfo,
                                      (DWORD)-1L,
                                      &dwEntriesRead,
                                      &dwTotalEntries,
                                      &hEnumHandle );
        if(dwError == ERROR_ACCESS_DENIED)
        {
            SetLastError(ERROR_ACCESS_DENIED);
            DISPLAY_MESSAGE(stderr,GetResString(IDS_ID_SHOW_ERROR));
            ShowLastError(stderr);
            FREE_LIBRARY(hModule);
            return FALSE;
        }
        if( dwError == NERR_Success || dwError == ERROR_MORE_DATA )
        {
            for ( DWORD dwFile = 0; 
                  dwFile < dwEntriesRead;
                  dwFile++, pFileInfo++ )
            {
                //Check whether the got open file is file or names pipe.
                // If named pipe leave it. As this utility do not 
                // disconnect Named pipe
                if ( IsNamedPipePath(pFileInfo->afpfile_path ) )
                {
                    continue;
                }
                else//Not a named pipe. is a file
                {   
                    bId = IsSpecifiedID(pszID,pFileInfo->afpfile_id ); 
                    bAccessedBy = IsSpecifiedAccessedBy(pszAccessedby, 
                                                   pFileInfo->afpfile_username );
                    bOpenmode = IsSpecifiedOpenmode(pszOpenmode,
                                                pFileInfo->afpfile_open_mode);
                    bOpenfile = IsSpecifiedOpenfile(pszOpenFile,
                                                pFileInfo->afpfile_path);
                    // Proceed for dicconecting the open file only if 
                    // all previous fuction returns true. This insures that
                    // user preference is taken care.

                    if( bId && 
                        bAccessedBy && 
                        bOpenmode && 
                        bOpenfile)
                    {
                        bIfatleast = TRUE;
                        memset( szResult, 0, (((MAX_RES_STRING*2) + 1) *
                                sizeof( TCHAR )) );



                        nStatus = AfpAdminFileClose(ulSFMServerConnection, 
                                                  pFileInfo->afpfile_id);
                        if(nStatus == NERR_Success)
                        {
                            // Create the output message string as File
                            // is successfully deleted.
                            // Output string will be :
                            // SUCCESS: Connection to openfile "filename"
                            // has been terminated.
                            bResult = TRUE;
                            //lstrcpy(szTemp,DISCONNECTED_SUCCESSFULLY);
                            //lstrcat(szResult,pFileInfo3_1->fi3_pathname);
                            //lstrcat(szResult,HAS_BEEN_TERMINATED);
                            
                            FORMAT_STRING(szResult,DISCONNECTED_SUCCESSFULLY,pFileInfo->afpfile_path);
                            DISPLAY_MESSAGE(stdout, szResult);

                            bResult = TRUE;
                        }
                        else
                        {
                           // As unable to disconnect the openfile make  
                           // output message as 
                           // ERROR: could not dissconnect "filename".
                            bResult = FALSE;
                            FORMAT_STRING(szResult,DISCONNECT_UNSUCCESSFUL,pFileInfo3_1->fi3_pathname);
                            DISPLAY_MESSAGE(stderr, szResult);
                        }
                    }//If bId...
                }//else part of is named pipe
             }
        }
   } while ( dwError == ERROR_MORE_DATA );

    if(bIfatleast == FALSE)// As not a single open file disconnected
                          // show Info. message as 
                          // INFO: No. open files found.
    {
        ShowMessage(stdout,GetResString(IDS_NO_D_OPENFILES));
    }

    // Free the block
    if( pFileInfo !=NULL)
    {
    NetApiBufferFree( pFileInfo); 
    pFileInfo = NULL;
    }

    FREE_LIBRARY(hModule);
    return TRUE;
}
/*-----------------------------------------------------------------------------

Routine Description:

Tests whether the given file path is namedpipe path or a file path

Arguments:

    [in] pszwFilePath    -- Null terminated string specifying the path name

Returned Value:

TRUE    - if it is a named pipe path
FALSE   - if it is a file path
-----------------------------------------------------------------------------*/
BOOL 
IsNamedPipePath(LPWSTR pszwFilePath)
{
    LPWSTR pwszSubString = NULL;
    pwszSubString = wcsstr(pszwFilePath, PIPE_STRING);//Search PIPE_STRING
    // If PIPE_STRING found then return TRUE else FALSE.
    if( pwszSubString == NULL)
    {
        return FALSE;
    }
   return TRUE;
}//IsNamedPipePath
/*-----------------------------------------------------------------------------

Routine Description:

Tests whether the user specified open file id is equivalent to the api 
returned id.

Arguments:

    [in]    pszId   -Null terminated string specifying the user 
                     specified fil ID 
    [in]    dwId    -current file ID.

Returned Value:

TRUE    - if pszId is * or equal to dwId
FALSE   - otherwise
-----------------------------------------------------------------------------*/
BOOL 
IsSpecifiedID(LPTSTR pszId, DWORD dwId)
{
   // Check if WILD card is given OR no id is given OR given id and 
   // id returned by api is similar. In any of the case return TRUE.
    
    if((lstrcmp(pszId, WILD_CARD) == 0) || 
       (lstrlen(pszId) == 0)||
       ((DWORD)(_ttol(pszId)) == dwId))
    {
        return TRUE;
    }
    return FALSE;
}//IsSpecifiedID
/*-----------------------------------------------------------------------------

Routine Description:

Tests whether the user specified accessed open file username is equivalent to 
the api returned username.

Arguments:

    [in]    pszAccessedby   - Null terminated string specifying the 
                              accessedby username
    [in]    pszwAccessedby  - Null terminated string specifying the api 
                              returned username.

Returned Value:

TRUE  - if pszAccessedby is * or equal to pszwAccessedby
FALSE - Otherwise
-----------------------------------------------------------------------------*/
BOOL 
IsSpecifiedAccessedBy(LPTSTR pszAccessedby, LPWSTR pszwAccessedby)
{
   // Check if WILD card is given OR non - existance of username  OR given 
   // username and  username returned by api is similar. In any of the case 
   // return TRUE.

    if((lstrcmp(pszAccessedby, WILD_CARD) == 0) || 
        (lstrlen(pszAccessedby) == 0)           ||
        (lstrcmpi(pszAccessedby,pszwAccessedby)==0))
    {
        return TRUE;
    }
    return FALSE;
}//IsSpecifiedAccessedBy
/*-----------------------------------------------------------------------------

Routine Description:

Tests whether the user specified open mode is equivalent to the api returned 
openmode

Arguments:

   [in] pszOpenmode - Null terminated string specifying the openmode
   [in] dwOpenmode  - The api returned open mode.

Returned Value:

TRUE  - if pszOpenmode is * or equal to dwOpenmode
FALSE - otherwise
-----------------------------------------------------------------------------*/
BOOL 
IsSpecifiedOpenmode(LPTSTR pszOpenmode, DWORD  dwOpenmode)
{
    
    // Check for WILD card if given OR if no open mode given . In both case 
    // return TRUE.
    if((lstrcmp(pszOpenmode, WILD_CARD) == 0) || 
       (lstrlen(pszOpenmode) == 0))
    {
        return TRUE;
    }
    // Check if READ mode is given as String . 
    if(CompareString(LOCALE_SYSTEM_DEFAULT,
                     NORM_IGNORECASE,
                     pszOpenmode,
                     -1,
                     READ_MODE,
                     -1)== CSTR_EQUAL)
    {
        // check  that only READ mode only with dwOpenmode variable which is
        // returned by api.
        if((PERM_FILE_READ == (dwOpenmode & PERM_FILE_READ)) && 
                       (PERM_FILE_WRITE != (dwOpenmode & PERM_FILE_WRITE)))
        {
            return TRUE;
        }
    }
    // Check if write mode is given.
    else if(CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
                         pszOpenmode,-1,WRITE_MODE,-1) == CSTR_EQUAL)
    {
        // check  that only WRITE mode only with dwOpenmode variable which is
        // returned by api.

        if((PERM_FILE_WRITE == (dwOpenmode & PERM_FILE_WRITE)) && 
            (PERM_FILE_READ != (dwOpenmode & PERM_FILE_READ)))
        {
            return TRUE;
        }
    }
    else if(CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
                        pszOpenmode,-1,READ_WRITE_MODE,-1) == CSTR_EQUAL)
    {
        if((PERM_FILE_READ == (dwOpenmode & PERM_FILE_READ)) && 
                       (PERM_FILE_WRITE == (dwOpenmode & PERM_FILE_WRITE)))
        {
            return TRUE;
        }
    }
    else if(CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
                        pszOpenmode,-1,WRITE_READ_MODE,-1) == CSTR_EQUAL)
    {
        if((PERM_FILE_WRITE == (dwOpenmode & PERM_FILE_WRITE)) && 
            (PERM_FILE_READ == (dwOpenmode & PERM_FILE_READ)))
        {
            return TRUE;
        }
    }

    // Given string does not matches with predefined Strings..
    // return FALSE.
    return FALSE;
}
/*-----------------------------------------------------------------------------

Routine Description:

Tests whether the user specified open file is equalant to the api returned 
open file.

Arguments:

    [in] pszOpenfile    - Null terminated string specifying the open 
                          file
    [in] pszwOpenfile   - Null terminated string specifying the api 
                          returned open file.

Returned Value:

TRUE    - if pszOpenfile is * or equal to pszwOpenfile
FALSE   - otherwise
-----------------------------------------------------------------------------*/
BOOL 
IsSpecifiedOpenfile(LPTSTR pszOpenfile, LPWSTR pszwOpenfile)
{
    // Check for WILD card if given OR no open file specified OR
    // open file given by user matches with open file returned by api. 
    // In all cases return TRUE.
    if((lstrcmp(pszOpenfile, WILD_CARD) == 0)||
       (lstrlen(pszOpenfile) == 0)           ||
       (lstrcmpi(pszwOpenfile,pszOpenfile)==0))
    {
        return TRUE;
    }
    return FALSE;
}//IsSpecifiedOpenfile