/*---------------------------------------------------------------------------*\
| MODULE: webptprn.cxx
|
|   This is the main entry-point module for the application.
|
|   Routines
|   --------
|   WinMain
|
|
| Copyright (C) 1996-1998 Hewlett Packard Company
| Copyright (C) 1996-1998 Microsoft Corporation
|
| history:
|   15-Dec-1996 <chriswil> created.
|
\*---------------------------------------------------------------------------*/

#include "webptprn.h"

#define memAlloc(cbSize)    (LPVOID)LocalAlloc(LPTR, cbSize)
#define memFree(pvMem)      LocalFree((LPVOID)pvMem)

#define strFree(pszStr) {if (pszStr) GlobalFree((HANDLE)pszStr);}

/*****************************************************************************\
* strAlloc
*
*   Allocates a string from the heap.  This pointer must be freed with
*   a call to strFree().
*
\*****************************************************************************/
LPTSTR strAlloc(
    LPCTSTR pszSrc)
{
    DWORD  cbSize;
    LPTSTR pszDst = NULL;


    cbSize = (pszSrc ? ((lstrlen(pszSrc) + 1) * sizeof(TCHAR)) : 0);

    if (cbSize) {

        if (pszDst = (LPTSTR)GlobalAlloc(GPTR, cbSize))
            CopyMemory(pszDst, pszSrc, cbSize);
    }

    return pszDst;
}


/*****************************************************************************\
* strLoad
*
*   Get string from resource based upon the ID passed in.
*
\*****************************************************************************/
LPTSTR strLoad(
    UINT ids)
{
    char szStr[MAX_RESBUF];


    if (LoadString(g_hInst, ids, szStr, sizeof(szStr)) == 0)
        szStr[0] = TEXT('\0');

    return strAlloc(szStr);
}


/*****************************************************************************\
* InitStrings
*
*
\*****************************************************************************/
BOOL InitStrings(VOID)
{
    g_szMsgAdd       = strLoad(IDS_MSG_ADD);
    g_szMsgDel       = strLoad(IDS_MSG_DEL);
    g_szMsgReboot    = strLoad(IDS_MSG_REBOOT);
    g_szMsgUninstall = strLoad(IDS_MSG_UNINSTALL);
    g_szMsgFailCpy   = strLoad(IDS_ERR_COPY);
    g_szMsgFailAdd   = strLoad(IDS_ERR_ADD);
    g_szMsgFailAsc   = strLoad(IDS_ERR_ASC);
    g_szRegDspVal    = strLoad(IDS_REG_DISPLAY);
    g_szMsgOsVerHead = strLoad(IDS_ERR_OSVERHEAD);
    g_szMsgOsVerMsg  = strLoad(IDS_ERR_OSVERMSG);


    return (g_szMsgAdd       &&
            g_szMsgDel       &&
            g_szMsgReboot    &&
            g_szMsgUninstall &&
            g_szMsgFailCpy   &&
            g_szMsgFailAdd   &&
            g_szMsgFailAsc   &&
            g_szRegDspVal    &&
            g_szMsgOsVerHead &&
            g_szMsgOsVerMsg
           );
}


/*****************************************************************************\
* FreeeStrings
*
*
\*****************************************************************************/
VOID FreeStrings(VOID)
{
    strFree(g_szMsgAdd);
    strFree(g_szMsgDel);
    strFree(g_szMsgReboot);
    strFree(g_szMsgUninstall);
    strFree(g_szMsgFailCpy);
    strFree(g_szMsgFailAdd);
    strFree(g_szMsgFailAsc);
    strFree(g_szRegDspVal);
    strFree(g_szMsgOsVerHead);
    strFree(g_szMsgOsVerMsg);
}


/*---------------------------------------------------------------------------*\
| pp_StrSize
|
|   Returns the bytes occupied by the string.
|
\*---------------------------------------------------------------------------*/
_inline DWORD pp_StrSize(
    LPCTSTR lpszStr)
{
    return (lpszStr ? ((lstrlen(lpszStr) + 1) * sizeof(TCHAR)) : 0);
}


/*---------------------------------------------------------------------------*\
| pp_AddFileAssociation
|
|   Add the .webpnp to the file-associations.
|
\*---------------------------------------------------------------------------*/
BOOL pp_AddFileAssociation(VOID)
{
    LONG lRet;
    HKEY hkPath;
    BOOL bRet = FALSE;


    lRet = RegCreateKeyEx(HKEY_CLASSES_ROOT,
                          g_szRegCabKey,
                          0,
                          NULL,
                          0,
                          KEY_WRITE,
                          NULL,
                          &hkPath,
                          NULL);

    if (lRet == ERROR_SUCCESS) {

        lRet = RegSetValueEx(hkPath,
                             NULL,
                             0,
                             REG_SZ,
                             (LPBYTE)g_szRegCabCmd,
                             pp_StrSize(g_szRegCabCmd));

        bRet = (lRet == ERROR_SUCCESS ? TRUE : FALSE);

        RegCloseKey(hkPath);
    }

    return bRet;
}


/*---------------------------------------------------------------------------*\
| pp_BuildName
|
|   Return a fully-qualified path/name.
|
\*---------------------------------------------------------------------------*/
LPTSTR pp_BuildName(
    LPCTSTR lpszPath,
    LPCTSTR lpszFile)
{
    DWORD  cbSize;
    LPTSTR lpszFull;

    static CONST TCHAR s_szFmt[] = TEXT("%s\\%s");


    // Calculate the size necessary to hold the full-path filename.
    //
    cbSize = pp_StrSize(lpszPath) + pp_StrSize(s_szFmt) + pp_StrSize(lpszFile);


    if (lpszFull = (LPTSTR)memAlloc(cbSize))
        wsprintf(lpszFull, s_szFmt, lpszPath, lpszFile);

    return lpszFull;
}


/*---------------------------------------------------------------------------*\
| pp_CurDir
|
|   Return CURRENT directory.
|
\*---------------------------------------------------------------------------*/
LPTSTR pp_CurDir(VOID)
{
    DWORD  cbSize;
    DWORD  cch;
    LPTSTR lpszDir = NULL;


    cbSize = GetCurrentDirectory(0, NULL);

    if (cbSize && (lpszDir = (LPTSTR)memAlloc(cbSize * sizeof(TCHAR)))) {

        GetCurrentDirectory(cbSize, lpszDir);

        if (cch = lstrlen(lpszDir)) {

            cch--;

            if (*(lpszDir + cch) == TEXT('\\'))
                *(lpszDir + cch) = TEXT('\0');
        }
    }

    return lpszDir;
}


/*---------------------------------------------------------------------------*\
| pp_SysDir
|
|   Return SYSTEM directory.
|
\*---------------------------------------------------------------------------*/
LPTSTR pp_SysDir(VOID)
{
    DWORD  cbSize;
    LPTSTR lpszDir = NULL;


    cbSize = GetSystemDirectory(NULL, 0);

    if (cbSize && (lpszDir = (LPTSTR)memAlloc(cbSize * sizeof(TCHAR))))
        GetSystemDirectory(lpszDir, cbSize);

    return lpszDir;
}


/*---------------------------------------------------------------------------*\
| pp_WinDir
|
|   Return WINDOWS directory.
|
\*---------------------------------------------------------------------------*/
LPTSTR pp_WinDir(VOID)
{
    DWORD  cbSize;
    LPTSTR lpszDir = NULL;


    cbSize = GetWindowsDirectory(NULL, 0);

    if (cbSize && (lpszDir = (LPTSTR)memAlloc(cbSize * sizeof(TCHAR))))
        GetWindowsDirectory(lpszDir, cbSize);

    return lpszDir;
}


/*---------------------------------------------------------------------------*\
| pp_TmpDir
|
|   Return TEMP directory.
|
\*---------------------------------------------------------------------------*/
LPTSTR pp_TmpDir(VOID)
{
    DWORD  cbSize;
    DWORD  cch;
    LPTSTR lpszDir = NULL;


    cbSize = GetTempPath(0, NULL);

    if (cbSize && (lpszDir = (LPTSTR)memAlloc(cbSize * sizeof(TCHAR)))) {

        GetTempPath(cbSize, lpszDir);

        if (cch = lstrlen(lpszDir)) {

            cch--;

            if (*(lpszDir + cch) == TEXT('\\'))
                *(lpszDir + cch) = TEXT('\0');
        }
    }

    return lpszDir;
}


/*---------------------------------------------------------------------------*\
| pp_AddCOM
|
|   This copies com-objects the destination directory.
|
\*---------------------------------------------------------------------------*/
BOOL pp_AddCOM(
    LPCTSTR lpszSDir,
    LPCTSTR lpszDDir,
    LPCTSTR lpszFile)
{
    LPTSTR lpszSrc;
    LPTSTR lpszDst;
    BOOL   bRet = FALSE;


    if (lpszSrc = pp_BuildName(lpszSDir, lpszFile)) {

        if (lpszDst = pp_BuildName(lpszDDir, lpszFile)) {

            bRet = CopyFile(lpszSrc, lpszDst, FALSE);

            memFree(lpszDst);
        }

        memFree(lpszSrc);
    }

    return bRet;
}


/*---------------------------------------------------------------------------*\
| pp_CopyFile
|
|   Copy the file to the temporary directory, then set up the wininit.ini
|   for delayed-boot-copy.
|
\*---------------------------------------------------------------------------*/
BOOL pp_CopyFile(
    LPCTSTR lpszCDir,
    LPCTSTR lpszSDir,
    LPCTSTR lpszTDir,
    LPCTSTR lpszFile)
{
    LPTSTR lpszSrc;
    LPTSTR lpszDst;
    LPTSTR lpszTmp;
    BOOL   bRet = FALSE;


    if (lpszSrc = pp_BuildName(lpszCDir, lpszFile)) {

        if (lpszDst = pp_BuildName(lpszSDir, lpszFile)) {

            if (lpszTmp = pp_BuildName(lpszTDir, lpszFile)) {

                if (CopyFile(lpszSrc, lpszTmp, FALSE)) {

                    bRet = WritePrivateProfileString(g_szRename,
                                                     lpszDst,
                                                     lpszTmp,
                                                     g_szFilInit);
                }

                memFree(lpszTmp);
            }

            memFree(lpszDst);
        }

        memFree(lpszSrc);
    }

    return bRet;
}


/*---------------------------------------------------------------------------*\
| pp_CopyFiles
|
|   This routine first copies the files to the temp-directory, then does
|   the necessary setup to have them copied upon boot.
|
\*---------------------------------------------------------------------------*/
BOOL pp_CopyFiles(VOID)
{
    LPTSTR lpszCDir;
    LPTSTR lpszSDir;
    LPTSTR lpszTDir;
    BOOL   bRet = FALSE;


    if (lpszCDir = pp_CurDir()) {

        if (lpszSDir = pp_SysDir()) {

            if (lpszTDir = pp_TmpDir()) {

                // Copy the oleprn to the system-directory in case this
                // is the first time of install.  This is necessary since
                // we do som COM-registration if called from WPNPINS.EXE.
                //
                pp_AddCOM(lpszCDir, lpszSDir, g_szFilOlePrn);


                // Copy the files to a temp-directory for installation
                // at boot-time.
                //
                if (pp_CopyFile(lpszCDir, lpszSDir, lpszTDir, g_szFilApp)    &&
                    pp_CopyFile(lpszCDir, lpszSDir, lpszTDir, g_szFilInetpp) &&
                    pp_CopyFile(lpszCDir, lpszSDir, lpszTDir, g_szFilOlePrn) &&
                    pp_CopyFile(lpszCDir, lpszSDir, lpszTDir, g_szFilInsEx)  &&
                    pp_CopyFile(lpszCDir, lpszSDir, lpszTDir, g_szFilIns16)  &&
                    pp_CopyFile(lpszCDir, lpszSDir, lpszTDir, g_szFilIns32)) {

                    bRet = TRUE;
                }

                memFree(lpszTDir);
            }

            memFree(lpszSDir);
        }

        memFree(lpszCDir);
    }

    return bRet;
}


/*---------------------------------------------------------------------------*\
| pp_AddProvidor
|
|   Adds the print-provider to the registry.
|
\*---------------------------------------------------------------------------*/
BOOL pp_AddProvidor(VOID)
{
    PROVIDOR_INFO_1 pi1;

    pi1.pName        = (LPTSTR)g_szPPName;
    pi1.pEnvironment = NULL;
    pi1.pDLLName     = (LPTSTR)g_szFilInetpp;

    return AddPrintProvidor(NULL, 1, (LPBYTE)&pi1);
}


/*---------------------------------------------------------------------------*\
| pp_AddRegistry
|
|   Writes out the uninstall-section in the registry.
|
\*---------------------------------------------------------------------------*/
BOOL pp_AddRegistry(VOID)
{
    HKEY hKey;
    HKEY hUns;
    LONG lRet;


    lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                        g_szRegUninstall,
                        0,
                        KEY_READ | KEY_WRITE,
                        &hKey);


    if (lRet == ERROR_SUCCESS) {

        lRet = RegOpenKeyEx(hKey,
                            g_szRegUnsKey,
                            0,
                            KEY_READ | KEY_WRITE,
                            &hUns);

        if (lRet != ERROR_SUCCESS) {

            lRet = RegCreateKeyEx(hKey,
                                  g_szRegUnsKey,
                                  0,
                                  NULL,
                                  0,
                                  KEY_WRITE,
                                  NULL,
                                  &hUns,
                                  NULL);

            if (lRet == ERROR_SUCCESS) {

                RegSetValueEx(hUns,
                              g_szRegDspNam,
                              0,
                              REG_SZ,
                              (LPBYTE)g_szRegDspVal,
                              pp_StrSize(g_szRegDspVal));

                RegSetValueEx(hUns,
                              g_szRegUnsNam,
                              0,
                              REG_SZ,
                              (LPBYTE)g_szRegUnsVal,
                              pp_StrSize(g_szRegUnsVal));

                RegCloseKey(hUns);
            }
        }

        RegCloseKey(hKey);
    }

    return (lRet == ERROR_SUCCESS);
}


/*---------------------------------------------------------------------------*\
| pp_DelProvidor
|
|   Removes the print-provider from the registry.
|
\*---------------------------------------------------------------------------*/
BOOL pp_DelProvidor(VOID)
{
    return DeletePrintProvidor(NULL, NULL, (LPTSTR)g_szPPName);
}


/*---------------------------------------------------------------------------*\
| pp_DelRegistry
|
|   Removes the uninstall registry settings.
|
\*---------------------------------------------------------------------------*/
BOOL pp_DelRegistry(VOID)
{
    HKEY hKey;
    LONG lRet;


    lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                        g_szRegUninstall,
                        0,
                        KEY_READ | KEY_WRITE,
                        &hKey);


    if (lRet == ERROR_SUCCESS) {

        lRet = RegDeleteKey(hKey, g_szRegUnsKey);

        RegCloseKey(hKey);
    }

    return (lRet == ERROR_SUCCESS);
}


/*---------------------------------------------------------------------------*\
| pp_DelFile
|
|   Remove the file from the system.
|
\*---------------------------------------------------------------------------*/
BOOL pp_DelFile(
    HANDLE  hFile,
    LPCTSTR lpszSDir,
    LPCTSTR lpszFile)
{
    LPTSTR lpszSrc;
    DWORD  cbWr;
    DWORD  cch;
    TCHAR  szBuf[MAX_BUFFER];
    BOOL   bRet = FALSE;


    if (lpszSrc = pp_BuildName(lpszSDir, lpszFile)) {

        cch = wsprintf(szBuf, TEXT("NUL=%s\r\n"), lpszSrc);

        bRet = WriteFile(hFile, szBuf, cch, &cbWr, NULL);

        memFree(lpszSrc);
    }

    return bRet;
}


/*---------------------------------------------------------------------------*\
| pp_DelFiles
|
|   Deletes the files from the system (delayed delete).
|
\*---------------------------------------------------------------------------*/
BOOL pp_DelFiles(VOID)
{
    HANDLE hFile;
    LPTSTR lpszWDir;
    LPTSTR lpszSDir;
    LPTSTR lpszWFile;
    DWORD  cch;
    DWORD  cbWr;
    TCHAR  szBuf[MAX_BUFFER];
    BOOL   bRet = FALSE;


    if (lpszWDir = pp_WinDir()) {

        if (lpszSDir = pp_SysDir()) {

            if (lpszWFile = pp_BuildName(lpszWDir, g_szFilInit)) {

                hFile = CreateFile(lpszWFile,
                                   GENERIC_READ | GENERIC_WRITE,
                                   0,
                                   NULL,
                                   CREATE_ALWAYS,
                                   FILE_ATTRIBUTE_NORMAL,
                                   NULL);

                if (hFile && (hFile != INVALID_HANDLE_VALUE)) {

                    cch = wsprintf(szBuf, TEXT("[%s]\r\n"), g_szRename);

                    WriteFile(hFile, szBuf, cch, &cbWr, NULL);

                    pp_DelFile(hFile, lpszSDir, g_szFilApp);
                    pp_DelFile(hFile, lpszSDir, g_szFilInetpp);
                    pp_DelFile(hFile, lpszSDir, g_szFilOlePrn);
                    pp_DelFile(hFile, lpszSDir, g_szFilInsEx);
                    pp_DelFile(hFile, lpszSDir, g_szFilIns16);
                    pp_DelFile(hFile, lpszSDir, g_szFilIns32);

                    CloseHandle(hFile);

                    bRet = TRUE;
                }

                memFree(lpszWFile);
            }

            memFree(lpszSDir);
        }

        memFree(lpszWDir);
    }

    return bRet;
}


/*---------------------------------------------------------------------------*\
| pp_Sync
|
|   Synchronize.  This will not return until the process is terminated.
|
\*---------------------------------------------------------------------------*/
BOOL pp_Sync(
    HANDLE hProcess)
{
    DWORD dwObj;
    DWORD dwExitCode = 0;


    while (TRUE) {

        dwObj = WaitForSingleObject(hProcess, INFINITE);


        // Look for the exit type.
        //
        switch (dwObj) {

        // The process handle triggered the wait.  Let's get the
        // exit-code and return whether the success.  Otherwise,
        // drop through and return the failure.
        //
        case WAIT_OBJECT_0:
            GetExitCodeProcess(hProcess, &dwExitCode);

            if (dwExitCode == 0)
                return TRUE;


        // Something failed in the call.  We failed.
        //
        case WAIT_FAILED:
            return FALSE;
        }
    }
}


/*---------------------------------------------------------------------------*\
| pp_Exec
|
|   Execute the process.
|
\*---------------------------------------------------------------------------*/
BOOL pp_Exec(
    LPCTSTR lpszComFile)
{
    PROCESS_INFORMATION pi;
    STARTUPINFO         sti;
    LPTSTR              lpszCmd;
    DWORD               cbSize;
    BOOL                bSuccess = FALSE;


    // Calculate enough space to hold the command-line arguments.
    //
    cbSize = (lstrlen(lpszComFile) + lstrlen(g_szExec) + 1) * sizeof(TCHAR);


    // Allocate the command-line for the create-process call.
    //
    if (lpszCmd = (LPTSTR)memAlloc(cbSize)) {

        // Initialize startup-info fields.
        //
        memset(&sti, 0, sizeof(STARTUPINFO));
        sti.cb = sizeof(STARTUPINFO);

        // Build the command-line string that exec's regsvr32.
        //
        wsprintf(lpszCmd, g_szExec, lpszComFile);


        // Exec the process.
        //
        if (EXEC_PROCESS(lpszCmd, &sti, &pi)) {

            CloseHandle(pi.hThread);

            // This will wait until the process if finished generating
            // the file.  The return from this indicates whether the
            // generation succeeded or not.
            //
            pp_Sync(pi.hProcess);

            CloseHandle(pi.hProcess);
        }

        memFree(lpszCmd);
    }

    return bSuccess;
}


/*---------------------------------------------------------------------------*\
| pp_DelCOM
|
|   Unregisters the COM object.
|
\*---------------------------------------------------------------------------*/
BOOL pp_DelCOM(VOID)
{
    LPTSTR lpszSDir;
    LPTSTR lpszDst;
    BOOL   bRet = FALSE;


    if (lpszSDir = pp_SysDir()) {

        if (lpszDst = pp_BuildName(lpszSDir, g_szFilOlePrn)) {

            pp_Exec(lpszDst);

            memFree(lpszDst);
        }

        memFree(lpszSDir);
    }

    return bRet;
}


/*---------------------------------------------------------------------------*\
| pp_DelPrinters
|
|   Deletes all the printers with URL-ports.
|
\*---------------------------------------------------------------------------*/
BOOL pp_DelPrinters(VOID)
{
    LPPRINTER_INFO_5 pi5;
    HANDLE           hPrn;
    DWORD            cbSize;
    DWORD            cPrt;
    DWORD            idx;
    DWORD            cch;
    BOOL             bRet = FALSE;


    // Get the size necessary to hold all enumerated printers.
    //
    cbSize = 0;
    EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &cbSize, &cPrt);


    if (cbSize && (pi5 = (LPPRINTER_INFO_5)memAlloc(cbSize))) {

        cPrt = 0;
        if (EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi5, cbSize, &cbSize, &cPrt)) {

            bRet = TRUE;

            for (idx = 0; idx < cPrt; idx++) {

                if ((_strnicmp((pi5+idx)->pPortName, g_szHttp , lstrlen(g_szHttp )) == 0) ||
                    (_strnicmp((pi5+idx)->pPortName, g_szHttps, lstrlen(g_szHttps)) == 0)) {

                    if (OpenPrinter((pi5+idx)->pPrinterName, &hPrn, NULL)) {

                        DeletePrinter(hPrn);

                        ClosePrinter(hPrn);
                    }
                }
            }
        }

        memFree(pi5);
    }

    return bRet;
}

/*---------------------------------------------------------- entry routine --*\
| WinMain
|
|   This is the process entry-point routine.  This is the basis for all
|   application events.
|
\*---------------------------------------------------------------------------*/
int PASCAL WinMain(
    HINSTANCE hInst,
    HINSTANCE hPrevInst,
    LPSTR     lpszCmd,
    int       nShow)
{
    OSVERSIONINFO OsVersion;
    int iRet = RC_WEXTRACT_AWARE;


    UNREFPARM(nShow);
    UNREFPARM(hPrevInst);

    g_hInst = hInst;

    if (InitStrings()) {

        OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    
        if (GetVersionEx(&OsVersion)) {  // If we can't get the OSVersion, we assume it's alright
            // Check that we are on Win9X, then check that the version is not millenium
            // We assume that millenium is Version 5 or higher            
            if (OsVersion.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS ||
                (OsVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && 
                   OsVersion.dwMajorVersion > 4 )) { 

                MessageBox( NULL, g_szMsgOsVerMsg, g_szMsgOsVerHead, MB_OK | MB_ICONINFORMATION);
                                                      
                goto cleanup;
            }
        }
       
        if (lpszCmd && (lstrcmpi(lpszCmd, g_szCmdUns) == 0)) {
            // We were asked to uninstall, not from inside WEXTRACT, so return 0 if we return
            iRet = 0;

            if (MessageBox(NULL, g_szMsgUninstall, g_szMsgDel, MB_YESNO | MB_ICONQUESTION) == IDYES) {

                pp_DelPrinters();
                pp_DelProvidor();
                pp_DelRegistry();
                pp_DelCOM();
                pp_DelFiles();

                if (MessageBox(NULL, g_szMsgReboot, g_szMsgDel, MB_YESNO | MB_ICONINFORMATION) == IDYES)
                    ExitWindowsEx(EWX_REBOOT, 0);
            }

        } else {

            if (pp_AddFileAssociation()) {

                if (pp_CopyFiles()) {

                    pp_AddProvidor();
                    pp_AddRegistry();

                    iRet |= REBOOT_YES | REBOOT_ALWAYS;

                } else {

                    MessageBox(NULL, g_szMsgFailCpy, g_szMsgAdd, MB_OK);
                }

            } else {

                MessageBox(NULL, g_szMsgFailAsc, g_szMsgAdd, MB_OK);
            }
        }

cleanup:

        FreeStrings();
    }

    return iRet;
}