/*++

Copyright (c) 1994  Microsoft Corporation

Module Name:

    report.c

Abstract:

    This module contains routines related to the REPORT generation.

Author:

    Jim Kelly (JimK) 22-Mar-1995

Revision History:

--*/

    
#include <secmgrp.h>


//
// There are several strings read in for use in the open-file
// dialog.  This defines the maximum length of those strings.
//

#define SECMGRP_REPORT_STRING_LENGTH                250





///////////////////////////////////////////////////////////////////////
//                                                                   //
//  Local Function Prototypes                                        //
//                                                                   //
///////////////////////////////////////////////////////////////////////


VOID
SecMgrpReportInitialize(
    IN  HWND                    hwnd
    );

LONG
SecMgrpDlgProcReport(
    HWND hwnd,
    UINT wMsg,
    DWORD wParam,
    LONG lParam
    );

/*
LONG
SecMgrpDlgProcInitReport(
    HWND hwnd,
    UINT wMsg,
    DWORD wParam,
    LONG lParam
    );
*/

VOID
SecMgrpDisplayReportFileName(
    IN  HWND                hwnd
    );

VOID
SecMgrpReportClose(
    IN  HWND                    hwnd
    );

VOID
SecMgrpReportOpen(
    IN  HWND                    hwnd
    );


///////////////////////////////////////////////////////////////////////
//                                                                   //
//  Module-wide variables                                            //
//                                                                   //
///////////////////////////////////////////////////////////////////////

//
// Used to indicate we have already initialized our module
//

SECMGR_STATIC
BOOL
    SecMgrpReportModuleInitialized = FALSE;


//
// If we have asked the user once whether or not they want to open
// a report before proceeding, and they say "no", then we assume they
// will always say no (at least until the next time they open/close
// a report) and we stop asking.  This variable is the way we detect
// whether they have said "no".
//

SECMGR_STATIC
BOOLEAN
    SecMgrpDeclinedReport = FALSE;


//
// Handle to the report file
//

SECMGR_STATIC
HANDLE
    SecMgrpReportFile;

//
// Title of Open File common dialog
//

SECMGR_STATIC        
TCHAR
    SecMgrpReportTitle[SECMGRP_REPORT_STRING_LENGTH];

//
// Name and title of open file
//

    TCHAR
        SecMgrpOpenFileName[_MAX_PATH],
        SecMgrpOpenFileTitle[_MAX_FNAME + _MAX_EXT];

//
// Displayed when no report file is open
//

SECMGR_STATIC
TCHAR
    SecMgrpReportNoFileOpen[SECMGR_SHORT_RESOURCE_STRING_LENGTH];






//
// Filter of file types for the open.
// In english, this should contain:
//
//      "Security Reports (*.SRP)", "*.srp"
//      "All files (*.*"),          "*.*"
//      ""
//
// However, some of these strings are localizable - so these must
// be filled in later from a string table.
//

SECMGR_STATIC
TCHAR
    SecMgrpReportOpenFilter[SECMGRP_REPORT_STRING_LENGTH];



SECMGR_STATIC
OPENFILENAME
    SecMgrpOpenInfo;





///////////////////////////////////////////////////////////////////////
//                                                                   //
//  Externally callable functions                                    //
//                                                                   //
///////////////////////////////////////////////////////////////////////

VOID
SecMgrPrintReportLine(
    IN  LPWSTR                      Line
    )
{

    BOOL
        Result;

    DWORD
        BytesWritten;


    if (SecMgrpReportActive) {

        Result = WriteFile( SecMgrpReportFile,
                            Line,
                            wcslen(Line)*sizeof(TCHAR),
                            &BytesWritten,
                            NULL
                            );
    }   
    return;
}


VOID
SecMgrpSuggestOpeningReport( 
    HWND    hwnd
    )

/*++

Routine Description:

    This function is used to query the user as to whether the user would
    like to open a report file before continuing.  This is expected to be
    called when SecMgrpReportActive is FALSE and the user is attempting to
    invoke some action from the main dialog.

Arguments

    hwnd - window handle.
    

Return Values:

    None.

--*/

{

    if (!SecMgrpReportActive && !SecMgrpDeclinedReport) {
        if (SecMgrpYesNoPopUp( hwnd, SECMGRP_POPUP_SUGGEST_REPORT, SECMGRP_POPUP_TITLE_SUGGEST_REPORT)) {
            SecMgrpButtonReport( hwnd );
        } else {
            SecMgrpDeclinedReport = TRUE;
        }
    }

    return;
}



VOID
SecMgrpButtonReport(
    HWND    hwnd
    )

/*++

Routine Description:

    This function is used to open a new report file.
    It will notify all smedlys of the new open if necessary.

Arguments

    hwnd - window handle.
    

Return Values:

    None.

--*/

{
    //
    // Make sure the report module has initialized
    //

    SecMgrpReportInitialize( hwnd );



    //
    // Start our dialog
    //

    DialogBoxParam(SecMgrphInstance,
            MAKEINTRESOURCE(SECMGR_ID_DLG_REPORT),
            hwnd,
            (DLGPROC)SecMgrpDlgProcReport,
            0);

    return;
}



///////////////////////////////////////////////////////////////////////
//                                                                   //
//  Module-wide functions                                            //
//                                                                   //
///////////////////////////////////////////////////////////////////////

VOID
SecMgrpReportInitialize(
    IN  HWND                    hwnd
    )

/*++

Routine Description:

    This function initializes the structure needed by the GetOpenFile()
    common dialog.


Arguments

    hwnd - parent window


Return Values:

    None.

--*/
{

    if (SecMgrpReportModuleInitialized == TRUE) {
        return;
    }

    //
    // Fill in the localizable strings in the open filter
    //

    LoadString( SecMgrphInstance,
                SECMGRP_STRING_REPORT_TITLE,
                SecMgrpReportTitle,
                SECMGRP_REPORT_STRING_LENGTH
                );

    LoadString( SecMgrphInstance,
                SECMGRP_STRING_REPORT_FILTER,
                SecMgrpReportOpenFilter,
                SECMGRP_REPORT_STRING_LENGTH
                );

    //
    // Used to indicate there is no file open
    //

    LoadString( SecMgrphInstance,
                SECMGRP_STRING_REPORT_NONE_OPEN,
                SecMgrpReportNoFileOpen,
                SECMGR_SHORT_RESOURCE_STRING_LENGTH
                );




    //
    // fill in the OpenFile structure
    //

    SecMgrpOpenInfo.lStructSize         = sizeof(OPENFILENAME);
    SecMgrpOpenInfo.hInstance           = SecMgrphInstance;
    SecMgrpOpenInfo.lpstrFilter         = SecMgrpReportOpenFilter;
    SecMgrpOpenInfo.lpstrCustomFilter   = NULL;
    SecMgrpOpenInfo.nMaxCustFilter      = 0;
    SecMgrpOpenInfo.nFilterIndex        = 0;
    SecMgrpOpenInfo.lpstrFile           = SecMgrpOpenFileName;
    SecMgrpOpenInfo.nMaxFile            = _MAX_PATH;
    SecMgrpOpenInfo.lpstrFileTitle      = SecMgrpOpenFileTitle;
    SecMgrpOpenInfo.nMaxFileTitle       = _MAX_FNAME + _MAX_EXT;
    SecMgrpOpenInfo.lpstrInitialDir     = NULL;                     // Start where we are
    SecMgrpOpenInfo.lpstrTitle          = SecMgrpReportTitle;
    SecMgrpOpenInfo.Flags               = OFN_CREATEPROMPT   |
                                          OFN_HIDEREADONLY;
    SecMgrpOpenInfo.nFileOffset         = 0;
    SecMgrpOpenInfo.nFileExtension      = 0;
    SecMgrpOpenInfo.lpstrDefExt         = L"spr";
    SecMgrpOpenInfo.lCustData           = 0;
    SecMgrpOpenInfo.lpfnHook            = NULL;
    SecMgrpOpenInfo.lpTemplateName      = NULL;


    SecMgrpReportModuleInitialized = TRUE;


    return;

}



LONG
SecMgrpDlgProcReport(
    HWND hwnd,
    UINT wMsg,
    DWORD wParam,
    LONG lParam
    )
/*++

Routine Description:

    This function is the dialog process for the [REPORT...] button.

Arguments



Return Values:

    TRUE - the message was handled.

    FALSE - the message was not handled.

--*/
{
    HWND
        Button;


    switch (wMsg) {

    case WM_INITDIALOG:

        SecMgrpDisplayReportFileName( hwnd );




        //
        // Set the cursor
        //

        Button = GetDlgItem(hwnd, IDOK);
        SendMessage(Button, CB_GETCURSEL, 0, 0);

        SetForegroundWindow(hwnd);
        ShowWindow(hwnd, SW_NORMAL);

        return(TRUE);



    case WM_SYSCOMMAND:
        switch (wParam & 0xfff0) {
        case SC_CLOSE:
            EndDialog(hwnd, 0);
            return(TRUE);
        }
        return(FALSE);



    case WM_COMMAND:
        switch(LOWORD(wParam)) {


            case IDCANCEL:
            case IDOK:
                EndDialog(hwnd, 0);
                return(TRUE);


            case SECMGR_ID_BUTTON_OPEN:
                SecMgrpReportOpen( hwnd );
                EndDialog(hwnd, 0);
                return(TRUE);


            case SECMGR_ID_BUTTON_CLOSE:
                SecMgrpReportClose( hwnd );
                SecMgrpDisplayReportFileName( hwnd );
                return(TRUE);


            default:
                return FALSE;
        }

    default:
        break;

    }

    return FALSE;
}



VOID
SecMgrpDisplayReportFileName(
    IN  HWND                hwnd
    )
{
    //
    // If there is currently a report file open, display its name.
    // Otherwise, display "No report file currently open".
    //

    if (SecMgrpReportActive) {
        SetDlgItemText( hwnd, SECMGR_ID_TEXT_CURRENT_REPORT, SecMgrpOpenFileName);
    } else {
        SetDlgItemText( hwnd, SECMGR_ID_TEXT_CURRENT_REPORT, SecMgrpReportNoFileOpen );
    }
    return;
}


VOID
SecMgrpReportClose(
    IN  HWND                    hwnd
    )
{
    BOOL
        Result;

    SecMgrpReportActive = FALSE;
    Result = CloseHandle( SecMgrpReportFile );
    ASSERT(Result);
    SecMgrpPopUp( hwnd, SECMGRP_POPUP_NOT_YET_AVAILABLE, SECMGRP_POPUP_TITLE_REPORT );
    return;
}



VOID
SecMgrpReportOpen(
    IN  HWND                    hwnd
    )
{
    DWORD
        Result,
        FileLength,
        FileLengthHigh;

    BOOL
        IgnoreResult;

    HANDLE
        CurrentFileHandle;


    //
    // Touch up the open-file structure
    //

    SecMgrpOpenInfo.hwndOwner           = hwnd;


    if (GetOpenFileName(&SecMgrpOpenInfo)) {


        //
        // If we already have an open report, close it now
        //

        if (SecMgrpReportActive) {
            SecMgrpReportActive = FALSE;
            IgnoreResult = CloseHandle( SecMgrpReportFile );
            ASSERT(IgnoreResult);
        }

        //
        // We have a file name.
        // Try to open it.
        //

        SecMgrpReportFile = CreateFile( SecMgrpOpenFileName,
                                        GENERIC_WRITE,                  // Desired Access
                                        FILE_SHARE_READ,                // Share mode
                                        NULL,                           // SecurityDescriptor
                                        OPEN_ALWAYS,                    // Open or create
                                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
                                        NULL
                                        );

        //
        // Make sure we opened a file...
        //

        if (SecMgrpReportFile == INVALID_HANDLE_VALUE) {

            //
            // Nope, post popup and go try again
            //

            SecMgrpPopUp( hwnd, SECMGRP_POPUP_REPORT_COULDNT_OPEN, SECMGRP_POPUP_TITLE_REPORT );
            PostMessage( hwnd, WM_COMMAND, SECMGR_ID_BUTTON_OPEN, 0);
            return;
        }




        //
        // See if the file was opened or created ...
        //
        //      GetLastError == 0                      (implies existing file opened)
        //      GetLastError == ERROR_ALREADY_EXISTS   (implies the fle already existed)
        //


        Result = GetLastError();

        if (Result == ERROR_ALREADY_EXISTS) {

            //
            // See if the file is empty.  If not, then notify that it will be appended to.
            // This also moves us to the end of the file.
            //

            FileLengthHigh = 0;
            FileLength = SetFilePointer( SecMgrpReportFile,     // handle of file
                                         0,                     // number of bytes to move file pointer
                                         &FileLengthHigh,       // address of high-order word of distance to move
                                         FILE_END               // how to move
                                         );

            //
            // Not sure what to do if we get an error, but let's check
            // and have an assert for debugging if nothing else.
            //

            if ((FileLength == 0xFFFFFFFF)  && (GetLastError() != NO_ERROR)) {

                //
                // SetFilePointer() failed ... hmmm
                //

                SecMgrpPopUp( hwnd, SECMGRP_POPUP_REPORT_FILE_ERROR, SECMGRP_POPUP_TITLE_REPORT );
                ASSERT(FALSE);
                IgnoreResult = CloseHandle( SecMgrpReportFile );
                SecMgrpReportActive = FALSE;

                //
                // Try again
                //

                PostMessage( hwnd, WM_COMMAND, SECMGR_ID_BUTTON_OPEN, 0);
                return;

            }


            if ((FileLength > 0) || (FileLengthHigh > 0)) {
                SecMgrpPopUp( hwnd, SECMGRP_POPUP_REPORT_FILE_EXISTS, SECMGRP_POPUP_TITLE_REPORT );
            }
        }


        //
        // We've opened a new report file.
        // Put out header information and then notify each smedly.
        //
        // This could take a while, so put up a message asking the user
        // to be patient.
        //

        SecMgrpReportActive = TRUE;
        
        DialogBoxParam(SecMgrphInstance,
                MAKEINTRESOURCE(SECMGR_ID_DLG_INIT_REPORT),
                hwnd,
                (DLGPROC)SecMgrpDlgProcInitReport,
                0);

DbgPrint("Report:  New report file opened and initialized.\n");

    }
    return;
}



LONG
SecMgrpDlgProcInitReport(
    HWND hwnd,
    UINT wMsg,
    DWORD wParam,
    LONG lParam
    )
/*++

Routine Description:

    This function is the dialog process for the dialog that informs the user
    that a new report file is being initialized.  It asks the user to be patient
    and then goes about notifying all the smedlys of the new report file.

Arguments

    None - all information is available in module-wide variables.


Return Values:


--*/
{
    HWND
        Button;

    HCURSOR
        hCursor;

    DWORD
        StringId,
        OutputLineLength;

    BOOL
        Result;

    TCHAR
        OutputLine[SECMGR_MAX_RESOURCE_STRING_LENGTH];


    switch (wMsg) {

    case WM_INITDIALOG:

        if (!SecMgrpReportActive) {
            EndDialog(hwnd, 0);
            return(TRUE);
        }


        SetForegroundWindow(hwnd);
        ShowWindow(hwnd, SW_NORMAL);

        //
        // Change the cursor to an hourglass
        //

        hCursor = SetCursor( LoadCursor(NULL, IDC_WAIT) );
        ShowCursor(TRUE);


        //
        // put header information in the new report file
        //


        //
        // time
        //

        LoadString( SecMgrphInstance,
                    SECMGRP_STRING_REPORT_TIME,
                    OutputLine,
                    sizeof(OutputLine)
                    );
        SecMgrPrintReportLine( OutputLine );

        OutputLineLength = GetTimeFormat( (SHORT)NtCurrentTeb()->CurrentLocale,
                                          TIME_FORCE24HOURFORMAT,     // Flags
                                          NULL,                       // use current time
                                          NULL,                       // Format for current locale
                                          OutputLine,                 // Receives time string
                                          sizeof(OutputLine)
                                          );
        ASSERT(OutputLineLength != 0);
        SecMgrPrintReportLine( OutputLine );


        //
        // Date
        //

        LoadString( SecMgrphInstance,
                    SECMGRP_STRING_REPORT_DATE,
                    OutputLine,
                    sizeof(OutputLine)
                    );
        SecMgrPrintReportLine( OutputLine );


        OutputLineLength = GetDateFormat( (SHORT)NtCurrentTeb()->CurrentLocale,
                                          0,                          // Flags
                                          NULL,                       // use current date
                                          NULL,                       // Format for current locale
                                          OutputLine,                 // Receives date string
                                          sizeof(OutputLine)
                                          );
        ASSERT(OutputLineLength != 0);
        SecMgrPrintReportLine( OutputLine );


        //
        // Machine
        //

        LoadString( SecMgrphInstance,
                    SECMGRP_STRING_REPORT_MACHINE,
                    OutputLine,
                    sizeof(OutputLine)
                    );
        SecMgrPrintReportLine( OutputLine );

        OutputLineLength = sizeof(OutputLine);
        Result = GetComputerName( OutputLine, &OutputLineLength );
        ASSERT(Result);
        SecMgrPrintReportLine( OutputLine );


        //
        // Security Level
        //

        SecMgrpReportSecurityLevel( SECMGRP_STRING_REPORT_LEVEL, SecMgrpCurrentLevel );



        SecMgrPrintReportLine( L"\n\n" );




        //
        // Now notify the smedlys
        // There are two passes.
        //      Pass 1 - Before we print out the summary list
        //      Pass 2 - After we print out the summary list
        //

        SecMgrpSmedlyReportFileChange( SecMgrpReportActive, 1 );    //Pass 1
        SecMgrpFillInItemList( TRUE, hwnd );
        SecMgrpSmedlyReportFileChange( SecMgrpReportActive, 2 );    //Pass 2

        //
        // That's it - we're done
        //

        EndDialog(hwnd, 0);
        return(TRUE);


    case WM_SYSCOMMAND:
        switch (wParam & 0xfff0) {
        case SC_CLOSE:
            EndDialog(hwnd, 0);
            return(TRUE);
        }

        return(FALSE);


    default:
        break;

    }

    return FALSE;
}



VOID
SecMgrpReportSecurityLevel(
    IN  DWORD               PrefixString,
    IN  ULONG               Level
    )
{
/*++

Routine Description:

    This function will place the specified security level in the report file.
    It may optionally be asked to place a prefix string in the report file
    before the security level is entered.
    

Arguments

    PrefixString - The ID of the prefix string to place in the report file.
        If this is zero (0), then no prefix string will be entered.

    Level - The level to place in the report file.



Return Values:


--*/
    DWORD
        StringId,
        OutputLineLength;

    TCHAR
        OutputLine[SECMGR_MAX_RESOURCE_STRING_LENGTH];

    if (PrefixString != 0) {
        LoadString( SecMgrphInstance,
                    PrefixString,
                    OutputLine,
                    sizeof(OutputLine)
                    );
        SecMgrPrintReportLine( OutputLine );
    }


    switch (Level) {
        case SECMGR_LEVEL_LOW:
            StringId = SECMGRP_STRING_LEVEL_LOW;
            break;

        case SECMGR_LEVEL_STANDARD:
            StringId = SECMGRP_STRING_LEVEL_STANDARD;
            break;

        case SECMGR_LEVEL_HIGH:
            StringId = SECMGRP_STRING_LEVEL_HIGH;
            break;

        case SECMGR_LEVEL_C2:
            StringId = SECMGRP_STRING_LEVEL_C2;
            break;
    } // end_switch

    LoadString( SecMgrphInstance,
                StringId,
                OutputLine,
                sizeof(OutputLine)
                );
    SecMgrPrintReportLine( OutputLine );

    SecMgrPrintReportLine( L"\n" );
}