/*++

Copyright (c) 1997 Microsoft Corporation

Module Name:

    faxocm.cpp

Abstract:

    This file implements the setup wizard code for the
    FAX server setup.

Environment:

        WIN32 User Mode

Author:

    Wesley Witt (wesw) 10-Sept-1997

--*/

#include "faxocm.h"
#pragma hdrstop


HINSTANCE hInstance;
SETUP_INIT_COMPONENT SetupInitComponent;

BOOL Unattended;
BOOL Upgrade;               // NT upgrade
BOOL Win9xUpgrade;          
BOOL NtGuiMode;
BOOL NtWorkstation;
BOOL UnInstall;
BOOL RemoteAdminSetup;
BOOL RebootRequired;
BOOL SuppressReboot;
WORD EnumPlatforms[4];
BOOL PointPrintSetup;
DWORD InstallThreadError;
BOOL OkToCancel;
DWORD CurrentCountryId;
LPWSTR CurrentAreaCode;
WCHAR ClientSetupServerName[MAX_PATH];
WCHAR ThisPlatformName[MAX_PATH];
DWORD InstalledPlatforms;
DWORD InstallType;
DWORD Installed;
BOOL ComponentInitialized;
WIZ_DATA WizData;
LPWSTR SourcePath;

PLATFORM_INFO Platforms[] =
{
    {  L"Windows NT x86",        L"i386",    0, FAX_INSTALLED_PLATFORM_X86,   NULL, FALSE },
    {  L"Windows NT Alpha_AXP",  L"alpha",   0, FAX_INSTALLED_PLATFORM_ALPHA, NULL, FALSE },
};

DWORD CountPlatforms = (sizeof(Platforms)/sizeof(PLATFORM_INFO));

UNATTEND_ANSWER UnattendAnswer[] =
{
   { L"FaxPrinterName",          DT_STRING,     0,          WizData.PrinterName         },
   { L"FaxNumber",               DT_STRING,     0,          WizData.PhoneNumber         },
   { L"RoutePrinterName",        DT_STRING,     0,          WizData.RoutePrinterName    },
   { L"RouteProfileName",        DT_STRING,     0,          WizData.RouteProfile        },
   { L"RouteFolderName",         DT_STRING,     0,          WizData.RouteDir            },
   { L"Csid",                    DT_STRING,     0,          WizData.Csid                },
   { L"Tsid",                    DT_STRING,     0,          WizData.Tsid                },
   { L"Rings",                   DT_LONGINT,    0,          &WizData.Rings              },
   { L"RouteToPrinter",          DT_BOOLEAN,    LR_PRINT,   &WizData.RoutingMask        },
   { L"RouteToInbox",            DT_BOOLEAN,    LR_INBOX,   &WizData.RoutingMask        },
   { L"RouteToFolder",           DT_BOOLEAN,    LR_STORE,   &WizData.RoutingMask        },
   { L"ArchiveOutgoing",         DT_BOOLEAN,    0,          &WizData.ArchiveOutgoing    },
   { L"ArchiveFolderName",       DT_STRING,     0,          WizData.ArchiveDir          }
};

#define CountUnattendAnswers  (sizeof(UnattendAnswer)/sizeof(UNATTEND_ANSWER))


extern "C" INT FaxDebugLevel;

extern "C"
DWORD
FaxOcmDllInit(
    HINSTANCE hInst,
    DWORD     Reason,
    LPVOID    Context
    )

/*++

Routine Description:

    DLL initialization function.

Arguments:

    hInstance   - Instance handle
    Reason      - Reason for the entrypoint being called
    Context     - Context record

Return Value:

    TRUE        - Initialization succeeded
    FALSE       - Initialization failed

--*/

{
    WCHAR DllName[MAX_PATH];


    if (Reason == DLL_PROCESS_ATTACH) {
        hInstance = hInst;
        DisableThreadLibraryCalls( hInstance );
        HeapInitialize( NULL, NULL, NULL, 0 );
        if (!GetModuleFileName(hInstance, DllName, MAX_PATH) || !LoadLibrary(DllName)) {
            return FALSE;
        }
        DebugPrint(( TEXT("faxocm loaded") ));
    }

    if (Reason == DLL_PROCESS_DETACH) {
        HeapCleanup();
    }

    return TRUE;
}


VOID
SetProgress(
    DWORD StatusString
    )
{
#ifdef NT5FAXINSTALL
    return;
#else
    SetupInitComponent.HelperRoutines.SetProgressText(
        SetupInitComponent.HelperRoutines.OcManagerContext,
        GetString( StatusString )
        );
    for (DWORD i=0; i<10; i++) {
        SetupInitComponent.HelperRoutines.TickGauge(
            SetupInitComponent.HelperRoutines.OcManagerContext
            );
    }
#endif
}


BOOL
SetWizData(
    VOID
    )
{
    HKEY hKey;
    LPWSTR RegisteredOwner = NULL;
    INFCONTEXT InfLine;
    WCHAR Id[128];
    WCHAR Value[128];
    DWORD i;
    HINF hInf;


    //
    // user name
    //

    hKey = OpenRegistryKey( HKEY_LOCAL_MACHINE, REGKEY_WINDOWSNT_CURRVER, TRUE, KEY_ALL_ACCESS );
    RegisteredOwner = GetRegistryString( hKey, REGVAL_REGISTERED_OWNER, EMPTY_STRING );
    RegCloseKey( hKey );

    if (RegisteredOwner && RegisteredOwner[0]) {
        wcscpy( WizData.UserName, RegisteredOwner );
        MemFree( RegisteredOwner );
    }

    //
    // fax printer name
    //

    wcscpy( WizData.PrinterName, GetString( IDS_DEFAULT_PRINTER_NAME ) );

    //
    // csid
    //

    wcscpy( WizData.Csid, GetString( IDS_DEFAULT_CSID ) );

    //
    // tsid
    //

    wcscpy( WizData.Tsid, GetString( IDS_DEFAULT_TSID ) );

    //
    // ring count
    //

    WizData.Rings = 2;

    //
    // routing mask
    //

    WizData.RoutingMask = LR_STORE;

    WizData.ArchiveOutgoing = TRUE;
    
    //
    // routing dir name
    //

    if (MyGetSpecialPath( CSIDL_COMMON_DOCUMENTS, WizData.RouteDir)) {
       ConcatenatePaths( WizData.RouteDir, GetString(IDS_RECEIVE_DIR) );
    }

    //
    // archive dir name
    //
    if (MyGetSpecialPath( CSIDL_COMMON_DOCUMENTS, WizData.ArchiveDir)) {
       ConcatenatePaths( WizData.ArchiveDir, GetString(IDS_ARCHIVE_DIR) );
    }


    //
    // process any unattend data
    //

    if (Unattended) {       
        
        hInf = SetupInitComponent.HelperRoutines.GetInfHandle(
            INFINDEX_UNATTENDED,
            SetupInitComponent.HelperRoutines.OcManagerContext
            );
        
        if (hInf == INVALID_HANDLE_VALUE) {
            return FALSE;
        }

        if (SetupFindFirstLine( hInf, L"Fax", NULL, &InfLine )) {
            DebugPrint((L"Processing fax unattend data"));
            do {
                SetupGetStringField( &InfLine, 0, Id, sizeof(Id)/sizeof(WCHAR), NULL );
                for (i=0; i<CountUnattendAnswers; i++) {
                    if (_wcsicmp( Id, UnattendAnswer[i].KeyName ) == 0) {
                        if ((SetupGetStringField( 
                                    &InfLine, 
                                    1, 
                                    Value, 
                                    sizeof(Value)/sizeof(WCHAR), 
                                    NULL )) &&
                            *Value) {
                        
                            switch (UnattendAnswer[i].DataType) {
                                case DT_STRING:
                                    wcscpy( (LPWSTR)UnattendAnswer[i].DataPtr, Value );
                                    break;
    
                                case DT_LONGINT:
                                    *((LPDWORD)UnattendAnswer[i].DataPtr) = wcstoul( Value, NULL, 0 );
                                    break;
    
                                case DT_BOOLEAN:
                                    if (UnattendAnswer[i].UseMaskOnBool) {
                                        if (_wcsicmp( Value, L"yes" ) == 0 || _wcsicmp( Value, L"true" ) == 0) {
                                            *((LPDWORD)UnattendAnswer[i].DataPtr) |= UnattendAnswer[i].UseMaskOnBool;
                                        }
                                    } else {
                                        if (_wcsicmp( Value, L"yes" ) == 0 || _wcsicmp( Value, L"true" ) == 0) {
                                            *((LPDWORD)UnattendAnswer[i].DataPtr) = TRUE;
                                        } else {
                                            *((LPDWORD)UnattendAnswer[i].DataPtr) = FALSE;
                                        }
                                    }
                                    break;
    
                                default:
                                    break;
                            }                        
                        }
                    }
                }
            } while(SetupFindNextLine( &InfLine, &InfLine ));
        }
    }

    return TRUE;
}


BOOL
IsGoodComponent(
    IN LPWSTR ComponentId,
    IN LPWSTR SubcomponentId,
    IN LPWSTR TargetId
    )
{
    if (ComponentId == NULL || SubcomponentId == NULL) {
        return FALSE;
    }
    if (_wcsicmp( ComponentId, TargetId ) == 0 && _wcsicmp( SubcomponentId, TargetId ) == 0) {
        return TRUE;
    }
    return FALSE;
}


DWORD
FaxOcmSetupProc(
    IN LPWSTR ComponentId,
    IN LPWSTR SubcomponentId,
    IN UINT Function,
    IN UINT Param1,
    IN OUT PVOID Param2
    )
{
    
    DebugPrint(( TEXT("FaxOcmSetup proc called with function 0x%08x"), Function ));

    switch( Function ) {

        case OC_PREINITIALIZE:
            return OCFLAG_UNICODE;

        case OC_SET_LANGUAGE:
            return TRUE;

        case OC_INIT_COMPONENT:
            if (OCMANAGER_VERSION <= ((PSETUP_INIT_COMPONENT)Param2)->OCManagerVersion) {
                ((PSETUP_INIT_COMPONENT)Param2)->ComponentVersion = OCMANAGER_VERSION;
            } else {
                return ERROR_CALL_NOT_IMPLEMENTED;
            }

            if (SetupInitComponent.SetupData.OperationFlags & SETUPOP_STANDALONE) {
                return 0;
            }

            //
            // eventhough this call happens once for each component that this
            // dll installs, we really only need to do our thing once.  this is
            // because the data that ocm passes is really the same for all calls.
            //

            if (!ComponentInitialized) {
                CopyMemory( &SetupInitComponent, (LPVOID)Param2, sizeof(SETUP_INIT_COMPONENT) );

                Unattended = (SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) > 0;
                Upgrade = (SetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) > 0;
                Win9xUpgrade = (SetupInitComponent.SetupData.OperationFlags & SETUPOP_WIN95UPGRADE) > 0;
                NtGuiMode = (SetupInitComponent.SetupData.OperationFlags & SETUPOP_STANDALONE) == 0;
                NtWorkstation = SetupInitComponent.SetupData.ProductType == PRODUCT_WORKSTATION;

                SourcePath = (LPWSTR) MemAlloc( StringSize(SetupInitComponent.SetupData.SourcePath) + MAX_PATH );
                if (!SourcePath) {
                    return ERROR_NOT_ENOUGH_MEMORY;
                }

                wcscpy( SourcePath, SetupInitComponent.SetupData.SourcePath );
                if (SourcePath[wcslen(SourcePath)-1] != L'\\') {
                    wcscat( SourcePath, L"\\" );
                }

                if (NtGuiMode) {
#ifdef _X86_
                    wcscat( SourcePath, L"i386" );
#endif
#ifdef _ALPHA_
                    wcscat( SourcePath, L"alpha" );
#endif
                } else {
                    SourcePath = VerifyInstallPath(SourcePath);                    
                    DebugPrint(( TEXT("faxocm Sourcepath = %s\n"),SourcePath));
                }

                DebugPrint((L"faxocm - SourcePath = %s", SourcePath));
                if (NtGuiMode) {
                    Unattended = TRUE;
                }

                //
                // make sure our inf file is opened by sysoc correctly
                // if it isn't then try to open it ourself
                //
                if (SetupInitComponent.ComponentInfHandle == NULL) {
                    WCHAR InfPath[MAX_PATH];
                    LPWSTR p;

                    GetModuleFileName( hInstance, InfPath, sizeof(InfPath)/sizeof(WCHAR) );
                    p = wcsrchr( InfPath, L'\\' );
                    if (p) {
                        wcscpy( p+1, L"faxsetup.inf" );
                        SetupInitComponent.ComponentInfHandle = SetupOpenInfFile( InfPath, NULL, INF_STYLE_WIN4, NULL );
                        if (SetupInitComponent.ComponentInfHandle == INVALID_HANDLE_VALUE) {
                            return ERROR_FILE_NOT_FOUND;
                        }
                    } else {
                        return ERROR_FILE_NOT_FOUND;
                    }
                }

                SetupOpenAppendInfFile( NULL, SetupInitComponent.ComponentInfHandle, NULL );

                InitializeStringTable();

                //
                // do minimal mapi initialization for NtGuiMode setup
                //
                MyInitializeMapi(NtGuiMode);
                 

                GetInstallationInfo( &Installed, &InstallType, &InstalledPlatforms );

                if (NtGuiMode && (IsNt4or351Upgrade() || Win9xUpgrade)) {
                    //
                    // in this case, we should treat this as a fresh install of fax
                    //
                    Upgrade = FALSE;
                }

                if (!NtGuiMode) {
                    Upgrade = Installed;
                }

                EnumPlatforms[PROCESSOR_ARCHITECTURE_INTEL] =  0;
                EnumPlatforms[PROCESSOR_ARCHITECTURE_ALPHA] =  1;

                ComponentInitialized = TRUE;

                SYSTEM_INFO si;
                GetSystemInfo( &si );
                if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
                    SetEnvironmentVariable( L"platform", L"i386" );
                } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA) {
                    SetEnvironmentVariable( L"platform", L"alpha" );
                }

                SetWizData();
            }

            return 0;

        case OC_QUERY_CHANGE_SEL_STATE:
            if (NtGuiMode || (!Installed) || UnInstall) {
                return 0;
            }
            UnInstall = Param1 == 0;
            return 1;

        case OC_REQUEST_PAGES:
            {
                PSETUP_REQUEST_PAGES SetupRequestPages = (PSETUP_REQUEST_PAGES) Param2;

                if (NtGuiMode) {
                    //
                    // never return pages during gui-mode setup
                    //
                    return 0;
                }

                if (_wcsicmp( ComponentId, COMPONENT_FAX ) != 0) {
                    return 0;
                }

                if (Param1 == WizPagesWelcome) {
#ifdef NT5FAXINSTALL
                    return 0;
#else
                    SetupRequestPages->Pages[0] = GetWelcomeWizardPage();
                    return 1;
#endif
                }

                if (Param1 == WizPagesMode) {
#ifdef NT5FAXINSTALL
                    return 0;
#else
                    SetupRequestPages->Pages[0] = GetEulaWizardPage();
                    return 1;
#endif
                }

                if (Param1 == WizPagesFinal) {
#ifdef NT5FAXINSTALL
                    return 0;
#else
                    SetupRequestPages->Pages[0] = GetFinalWizardPage();
                    return 1;
#endif
                }
            }
            break;

        case OC_CALC_DISK_SPACE:
            if (NtGuiMode && !Upgrade) {
                CalcServerDiskSpace(
                    SetupInitComponent.ComponentInfHandle,
                    (HDSKSPC) Param2,
                    NULL,
                    Param1
                    );
            }
            break;

        case OC_QUEUE_FILE_OPS:
            if (!SubcomponentId || !*SubcomponentId) {
                return 0;
            }
            if (NtGuiMode && !Upgrade) {
                AddServerFilesToQueue(
                    SetupInitComponent.ComponentInfHandle,
                    (HSPFILEQ) Param2,
                    NULL
                    );
            }
            break;

        case OC_COMPLETE_INSTALLATION:
            if (!SubcomponentId || !*SubcomponentId) {
                return 0;
            }
            
            if (NtGuiMode) {
            
                ServerInstallation(
                    SetupInitComponent.HelperRoutines.QueryWizardDialogHandle(
                        SetupInitComponent.HelperRoutines.OcManagerContext
                        ),
                    SourcePath
                    );
            }
            break;

        case OC_QUERY_STEP_COUNT:
            if (!SubcomponentId || !*SubcomponentId) {
                return 0;
            }
            return ServerGetStepCount() * 10;

        case OC_CLEANUP:
            break;

        default:
            break;
    }

    return 0;
}