// Printer.cpp: implementation of the CPrinter class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Printer.h"
#include "wininet.h"

static const DWORD BIT_IGNORED_JOB = (JOB_STATUS_PAUSED   |
                                      JOB_STATUS_PRINTED  |
                                      JOB_STATUS_DELETING |
                                      JOB_STATUS_OFFLINE  |
                                      JOB_STATUS_SPOOLING);
static const DWORD BIT_ERROR_JOB   = (JOB_STATUS_ERROR | JOB_STATUS_PAPEROUT);
static const DWORD CHAR_PER_PAGE   = 4800;
static const DWORD PAGEPERJOB      = 1;
static const DWORD BYTEPERJOB      = 2;


#ifdef WIN9X
    #error This code requires DRIVER_INFO_6 which is not availabe under Win9X
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPrinter::CPrinter():
          m_hPrinter(NULL),
          m_pInfo2(NULL),
          m_pInfo4(NULL),
          m_pDriverInfo6(NULL),
          m_bCalcJobETA(NULL),
          m_pszUrlBuffer(NULL),
          m_pszOemUrl (NULL),
          m_pszManufacturer (NULL)
{
}

CPrinter::~CPrinter()
{
    if (m_pInfo2) {
        LocalFree (m_pInfo2);
    }

    if (m_pInfo4) {
        LocalFree (m_pInfo4);
    }

    if (m_pDriverInfo6) {
        LocalFree (m_pDriverInfo6);
    }

    if (m_hPrinter) {
        ClosePrinter (m_hPrinter);
    }

    if (m_pszUrlBuffer) {
        LocalFree (m_pszUrlBuffer);
    }

    if (m_pszOemUrl) {
        LocalFree (m_pszOemUrl);
    }

    if (m_pszManufacturer) {
        LocalFree (m_pszManufacturer);
    }

}

BOOL CPrinter::Open(LPTSTR pPrinterName, LPHANDLE phPrinter)
{
    PRINTER_DEFAULTS pd = {NULL, NULL, PRINTER_ACCESS_USE};

    if (m_hPrinter != NULL)
        return FALSE;

    if (! (OpenPrinter(pPrinterName, &m_hPrinter, &pd)))
        return FALSE;

    if (phPrinter) {
        *phPrinter = m_hPrinter;
    }

    return TRUE;
}

// This is a compiler safe way of checking that an unsigned integer is
// negative and returning zero if it is or the integer if it is not
// Note: Tval can be any size but must be unsigned
template<class T> inline T ZeroIfNegative(T Tval) {
    if (Tval & (T(1) << (sizeof(Tval) * 8 - 1))) return 0;
        else return Tval;
}

BOOL CPrinter::CalJobEta()
{
    DWORD           dwPrintRate = DWERROR;
    PJOB_INFO_2     pJobInfo = NULL;
    PJOB_INFO_2     pJob;
    DWORD           dwNumJobs;
    DWORD           dwNeeded = 0;
    DWORD           i;
    float           fFactor = 1;
    float           fTotal = 0;
    DWORD           dwNumJobsReqested;
    BOOL            bRet = FALSE;
    const   DWORD   cdwLimit = 256;

    if (! AllocGetPrinterInfo2())
        return NULL;

    if (m_pInfo2->cJobs > 0) {

        if (m_pInfo2->cJobs > cdwLimit) {
            fFactor = (float) m_pInfo2->cJobs / cdwLimit;
            dwNumJobsReqested = cdwLimit;
        }
        else
            dwNumJobsReqested = m_pInfo2->cJobs;

        EnumJobs (m_hPrinter, 0, dwNumJobsReqested, 2,
            NULL, 0, &dwNeeded, &dwNumJobs);

        if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
            (NULL == (pJobInfo = (PJOB_INFO_2)LocalAlloc(LPTR, dwNeeded))) ||
            (!EnumJobs (m_hPrinter, 0, dwNumJobsReqested, 2, (LPBYTE) pJobInfo, dwNeeded,
            &dwNeeded, &dwNumJobs))) {

            goto Cleanup;
        }

        // Get the average Job size

        // Find out if we can use page as the unit
        for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
            if (pJob->Status & BIT_IGNORED_JOB)
                continue;

            if (pJob->Size > 0 && pJob->TotalPages == 0)
                break;
        }

        m_dwPendingJobCount = 0;

        if (i == dwNumJobs) {
            // All the jobs have the page information. Use page as the unit
            m_dwAvgJobSizeUnit = PAGEPERJOB;

            for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
                if (pJob->Status & BIT_IGNORED_JOB)
                    continue;
                m_dwPendingJobCount++;
                fTotal += pJob->TotalPages;
            }
        }
        else {
            // Use byte as the unit
            m_dwAvgJobSizeUnit = BYTEPERJOB;
            for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
                if (pJob->Status & BIT_IGNORED_JOB)
                    continue;
                m_dwPendingJobCount++;
                fTotal += ZeroIfNegative(pJob->Size);
            }
        }

        // Calculate the averate job size
        if (m_dwPendingJobCount) {
            m_dwAvgJobSize = DWORD ((fTotal) / (float) m_dwPendingJobCount);
            dwPrintRate = GetPPM();

            if (dwPrintRate != DWERROR)
                m_dwJobCompletionMinute = (DWORD) (fFactor * GetWaitingMinutes (dwPrintRate, pJobInfo, dwNumJobs));
        }
        else {
            m_dwAvgJobSize = 0;
            m_dwJobCompletionMinute = 0;
        }

        m_dwPendingJobCount = (DWORD) (m_dwPendingJobCount * fFactor);
    }
    else {
        m_dwPendingJobCount = 0;
        m_dwAvgJobSize = 0;
        m_dwJobCompletionMinute = 0;
        m_dwAvgJobSizeUnit = PAGEPERJOB;
    }

    m_bCalcJobETA = TRUE;

    // Set the last error to ERROR_INVALID_DATA if the printer rate is not available for the current printer
    // or if the printer status is not suitable to display the summary information
    //

    if (dwPrintRate == DWERROR ||
        m_pInfo2->Status & ( PRINTER_STATUS_PAUSED           |
                             PRINTER_STATUS_ERROR            |
                             PRINTER_STATUS_PENDING_DELETION |
                             PRINTER_STATUS_PAPER_JAM        |
                             PRINTER_STATUS_PAPER_OUT        |
                             PRINTER_STATUS_OFFLINE )) {
        SetLastError (ERROR_INVALID_DATA);
        m_dwJobCompletionMinute = DWERROR;
        bRet = FALSE;
    }
    else
        bRet = TRUE;

Cleanup:
    if (pJobInfo)
        LocalFree(pJobInfo);
    return bRet;

    }

DWORD CPrinter::GetWaitingMinutes(DWORD dwPPM, PJOB_INFO_2 pJobInfo, DWORD dwNumJob)
{
    DWORD   dwWaitingTime   = 0;
    DWORD   dwTotalPages    = 0;

    if (dwNumJob == 0)
        return 0;

    if (dwPPM == 0)
        return DWERROR;

    for (DWORD i = 0; i < dwNumJob; i++,  pJobInfo++) {
        if (pJobInfo->Status & BIT_IGNORED_JOB)
            continue;
        if (pJobInfo->Status & BIT_ERROR_JOB)
            return DWERROR;

        if (pJobInfo->TotalPages > 0) {
            dwTotalPages += pJobInfo->TotalPages;
        }
        else {
            if (pJobInfo->Size) {
                dwTotalPages += 1 + ZeroIfNegative(pJobInfo->Size) / CHAR_PER_PAGE;
            }
        }
    }

    if (dwTotalPages)
        dwWaitingTime = 1 + dwTotalPages / dwPPM;

    return dwWaitingTime;
}


DWORD CPrinter::GetPPM()
{
    DWORD dwPrintRate;
    DWORD dwPrintRateUnit;

    // Get PrintRate
    dwPrintRate = MyDeviceCapabilities(m_pInfo2->pPrinterName,
                                     NULL,
                                     DC_PRINTRATE,
                                     NULL,
                                     NULL);

    if (dwPrintRate == DWERROR ) {
        return dwPrintRate;
    }

    dwPrintRateUnit = MyDeviceCapabilities(m_pInfo2->pPrinterName,
                                         NULL,
                                         DC_PRINTRATEUNIT,
                                         NULL,
                                         NULL);

    switch (dwPrintRateUnit) {
    case PRINTRATEUNIT_PPM:         // PagesPerMinute
        break;
    case PRINTRATEUNIT_CPS:         // CharactersPerSecond
        dwPrintRate = CPS2PPM (dwPrintRate);
        break;
    case PRINTRATEUNIT_LPM:         // LinesPerMinute
        dwPrintRate = LPM2PPM (dwPrintRate);
        break;
    case PRINTRATEUNIT_IPM:         // InchesPerMinute
        dwPrintRate  = DWERROR;
        break;
    default:                        // Unknown
        dwPrintRate  = DWERROR;
        break;
    }

    return dwPrintRate ;
}

BOOL CPrinter::AllocGetPrinterInfo2()
{

    DWORD               dwNeeded = 0;
    PPRINTER_INFO_2     pPrinterInfo = NULL;
    LPTSTR              pszTmp;


    if (m_hPrinter == NULL) {
        SetLastError (ERROR_INVALID_HANDLE);
        return FALSE;
    }

    // Get a PRINTER_INFO_2 structure filled up

    if (GetPrinter(m_hPrinter, 2, NULL, 0, &dwNeeded) ||
        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
        (NULL == (pPrinterInfo = (PPRINTER_INFO_2)LocalAlloc(LPTR, dwNeeded))) ||
        (!GetPrinter(m_hPrinter, 2, (byte *)pPrinterInfo, dwNeeded, &dwNeeded))) {

            if (pPrinterInfo)
                LocalFree(pPrinterInfo);

            if (! GetLastError())
                SetLastError (ERROR_INVALID_DATA);
            return FALSE;
    }

    // Mark the offline status if the attribute says offline
    if (pPrinterInfo->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) {
        pPrinterInfo->Status |= PRINTER_STATUS_OFFLINE;
    }

    // Extract the first port for the case of pooled printing. i.e. we don't support pooled printing.
    if ( pPrinterInfo->pPortName) {
        if( pszTmp = _tcschr( pPrinterInfo->pPortName, TEXT(',')))
            *pszTmp = TEXT('\0');
    }

    if (m_pInfo2) {
        LocalFree (m_pInfo2);
    }

    m_pInfo2 = pPrinterInfo;

    return TRUE;
}

BOOL CPrinter::AllocGetPrinterInfo4()
{

    DWORD               dwNeeded = 0;
    PPRINTER_INFO_4     pPrinterInfo = NULL;

    if (m_hPrinter == NULL) {
        SetLastError (ERROR_INVALID_HANDLE);
        return FALSE;
    }

    // Get a PRINTER_INFO_4 structure filled up

    if (GetPrinter(m_hPrinter, 4, NULL, 0, &dwNeeded) ||
        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
        (NULL == (pPrinterInfo = (PPRINTER_INFO_4)LocalAlloc(LPTR, dwNeeded))) ||
        (!GetPrinter(m_hPrinter, 4, (byte *)pPrinterInfo, dwNeeded, &dwNeeded))) {

            if (pPrinterInfo)
                LocalFree(pPrinterInfo);

            if (! (GetLastError()))
                SetLastError (ERROR_INVALID_DATA);
            return FALSE;
    }

    if (m_pInfo4) {
        LocalFree (m_pInfo4);
    }
    m_pInfo4 = pPrinterInfo;

    return TRUE;
}

BOOL CPrinter::AllocGetDriverInfo6()
{

    DWORD               dwNeeded = 0;
    PDRIVER_INFO_6      pDriverInfo = NULL;

    if (m_hPrinter == NULL) {
        SetLastError (ERROR_INVALID_HANDLE);
        return FALSE;
    }

    // Get a DRIVER_INFO_6 structure filled up

    if (GetPrinterDriver(m_hPrinter, NULL, 6, NULL, 0, &dwNeeded) ||
        (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
        (NULL == (pDriverInfo = (PDRIVER_INFO_6)LocalAlloc(LPTR, dwNeeded))) ||
        (!GetPrinterDriver(m_hPrinter, NULL, 6, (LPBYTE)pDriverInfo, dwNeeded, &dwNeeded))) {

            if (pDriverInfo)
                LocalFree(pDriverInfo);

            if (! (GetLastError()))
                SetLastError (ERROR_INVALID_DATA);
            return FALSE;
    }

    if (m_pDriverInfo6) {
        LocalFree (m_pDriverInfo6);
    }
    m_pDriverInfo6 = pDriverInfo;

    return TRUE;
}


PPRINTER_INFO_2 CPrinter::GetPrinterInfo2()
{
    if (m_pInfo2 == NULL) {
        if (! AllocGetPrinterInfo2())
            return NULL;
    }

    return m_pInfo2;
}

PDRIVER_INFO_6 CPrinter::GetDriverInfo6()
{
    if (m_pDriverInfo6 == NULL) {
        if (! AllocGetDriverInfo6()) {
            return NULL;
        }
    }

    return m_pDriverInfo6;
}


DWORD CPrinter::GetWaitingTime()
{
    if (!m_bCalcJobETA) {
        SetLastError (ERROR_INVALID_DATA);
        return FALSE;
    }
    return m_dwJobCompletionMinute;
}

BOOL CPrinter::GetJobEtaData (DWORD & dwWaitingTime, DWORD &dwJobCount, DWORD &dwJobSize, DWORD &dwJob)
{
    if (!m_bCalcJobETA) {
        SetLastError (ERROR_INVALID_DATA);
        return FALSE;
    }

    dwJobCount    = m_dwPendingJobCount;
    dwJobSize     = m_dwAvgJobSize;
    dwWaitingTime = m_dwJobCompletionMinute;
    dwJob         = m_dwAvgJobSizeUnit;

    return TRUE;
}


LPTSTR CPrinter::GetPrinterWebUrl(void)
{
    static const TCHAR c_szHttp[]   = TEXT("http://");
    static const TCHAR c_szHttps[]  = TEXT("https://");

    BOOL                bReturn = FALSE;
    DWORD               dwLastError = ERROR_SUCCESS;
    DWORD               dwLen       = 0;
    TCHAR               szBuffer[MAX_COMPUTERNAME_LENGTH+1];
    DWORD               dwBufferSize;
    DWORD               dwAttributes;
    LPCTSTR             pszServerName;
    LPTSTR              pszShareName;
    LPTSTR              pszSplServerName;
    LPTSTR              pszSplPrinterName;
    LPTSTR              pszSplShareName;

    //
    // Get printer info 4 to fetch the attribute.
    //
    bReturn = AllocGetPrinterInfo4();

    if (!bReturn) {

        if (GetLastError () == ERROR_INVALID_LEVEL ) {
            //
            // Most likely it is a remote printers folder, no support for level4, so
            // we have to use level 2 instead.
            //
            if (! AllocGetPrinterInfo2())
                goto Cleanup;
        }
        else {
            //
            // The call fails with other reasons
            //
            goto Cleanup;
        }

    }
    else{

        if (m_pInfo4->Attributes & PRINTER_ATTRIBUTE_LOCAL) {
            // Check if the local flag is on. If so, try to get printer info2 for more information
            if (! AllocGetPrinterInfo2())
                goto Cleanup;
        }
    }

    //
    // Assume failure
    //
    bReturn = FALSE;


    if (m_pInfo2) {
        dwAttributes = m_pInfo2->Attributes;
        pszSplServerName = m_pInfo2->pServerName;
        pszSplPrinterName = m_pInfo2->pPrinterName;
        pszSplShareName = m_pInfo2->pShareName;
    }
    else
    {
        dwAttributes = m_pInfo4->Attributes;
        pszSplServerName = m_pInfo4->pServerName;
        pszSplPrinterName = m_pInfo4->pPrinterName;
        pszSplShareName = NULL;
    }

    //
    // Check if it is a printer connected to an http port
    // then the port name is the url.
    //
    if( m_pInfo2 )
    {

        if( m_pInfo2->pPortName )
        {
            //
            // Compare the port name prefex to see if it is an HTTP port.
            //
            if( !_tcsnicmp( m_pInfo2->pPortName, c_szHttp, _tcslen( c_szHttp ) ) ||
                !_tcsnicmp( m_pInfo2->pPortName, c_szHttps, _tcslen( c_szHttps ) ) )
            {
                //
                //  We always use portname as the URL
                //
                dwLen = 1 + lstrlen( m_pInfo2->pPortName );

                if (! (m_pszUrlBuffer = (LPTSTR) LocalAlloc (LPTR, dwLen * sizeof (TCHAR))))
                {
                    goto Cleanup;
                }


                lstrcpy( m_pszUrlBuffer, m_pInfo2->pPortName );

                bReturn = TRUE;
                goto Cleanup;


            }
        }
    }


    //
    // If it is an unshared printer, return false
    //
    if ( !(dwAttributes & PRINTER_ATTRIBUTE_SHARED) )
    {
        goto Cleanup;
    }


    //
    // Check if it is a connection or a local printer or a masq printer
    // which is not connected over http, then build the url
    // from the \\server name\share name.
    //
    if( !pszSplServerName )
    {
        dwBufferSize = COUNTOF( szBuffer );

        if( !GetComputerName( szBuffer, &dwBufferSize ) )
        {
            goto Cleanup;
        }

        pszServerName = szBuffer;
    }
    //
    // Server name was provided then set our pointer to just
    // after the two leading wacks.
    //
    else
    {
        if( pszSplServerName[0] == TEXT('\\') &&
            pszSplServerName[1] == TEXT('\\') )
        {
            pszServerName = pszSplServerName + 2;
        }
        else
        {
            goto Cleanup;
        }
    }

    if ( !IsWebServerInstalled(pszSplServerName) ) {

        dwLastError = ERROR_NO_BROWSER_SERVERS_FOUND;
        goto Cleanup;
    }

    //
    // Build the URL -  http://server/printers/ipp_0004.asp?printer=ShareName
    //
    if (pszSplShareName)
    {
        pszShareName = pszSplShareName;
    }
    else {
        //
        //  Parse the sharename/printername  from the printer name
        //
        if(pszSplPrinterName) {
            if (pszSplPrinterName[0] == TEXT ('\\') && pszSplPrinterName[1] == TEXT ('\\') )
            {
                pszShareName = _tcschr (pszSplPrinterName + 2, TEXT ('\\'));
                pszShareName++;
            }
            else
                pszShareName = pszSplPrinterName;
        }
        else
        {
            goto Cleanup;
        }
    }

    GetWebUIUrl  (pszServerName, pszShareName, NULL, &dwLen);

    if (GetLastError () != ERROR_INSUFFICIENT_BUFFER )
    {
        goto Cleanup;
    }

    if (! (m_pszUrlBuffer = (LPTSTR) LocalAlloc (LPTR, dwLen * sizeof (TCHAR))))
    {
        goto Cleanup;
    }

    if (!GetWebUIUrl  (pszServerName, pszShareName, m_pszUrlBuffer, &dwLen))
    {
        goto Cleanup;
    }

    //
    // Indicate success.
    //
    bReturn = TRUE;

    //
    // Clean any opened or allocated resources.
    //
Cleanup:


    //
    // If this routine failed then set the last error.
    //
    if( !bReturn )
    {
        //
        // If the last error was not set then a called routine may
        // have set the last error.  We don't want to clear the
        // last error.
        //
        if( dwLastError != ERROR_SUCCESS )
        {
            SetLastError( dwLastError );
        }
    }
    return m_pszUrlBuffer;
}

BOOL CPrinter::GetDriverData(
    DriverData dwDriverData,
    LPTSTR &pszData)
{
    static const ULONG_PTR ulpOffset[LastDriverData] = {
        // This has the offsets into the DRIVER_INFO_6 structure.....
        ULOFFSET( PDRIVER_INFO_6, pszOEMUrl )     ,
        ULOFFSET( PDRIVER_INFO_6, pszHardwareID ) ,
        ULOFFSET( PDRIVER_INFO_6, pszMfgName)
    };

    LPTSTR pszDataString = NULL;
    BOOL   bRet          = FALSE;
    DWORD  dwSize;

    ASSERT( (int)dwDriverData >= 0 && (int)dwDriverData < LastDriverData );

    if (! GetDriverInfo6() )
        goto Cleanup;

    pszDataString = *(LPTSTR *)(((ULONG_PTR) m_pDriverInfo6) +  ulpOffset[dwDriverData] );

    if (pszDataString == NULL || *pszDataString == NULL)
        goto Cleanup;

    dwSize = sizeof(TCHAR) * (lstrlen( pszDataString ) + 1);

    if (! (pszData  = (LPTSTR)LocalAlloc(LPTR, dwSize)))
        goto Cleanup;

    lstrcpy( pszData, pszDataString);

    bRet = TRUE;
Cleanup:
    return bRet;
}

BOOL CPrinter::ParseUrlPattern(
    LPTSTR pSrc,
    LPTSTR pDest,
    DWORD &dwDestLen)
{
    const dwMaxMacroLen = 255;
    enum {
        NORMALTEXT, STARTMACRO
    } URL_PATTERN_STATE;


    BOOL bRet = FALSE;
    DWORD dwLen = 0;
    DWORD dwMacroLen = 0;
    DWORD dwAvailbleSize;
    DWORD dwState = NORMALTEXT;
    int i;
    TCHAR ch;
    TCHAR szMacroName [dwMaxMacroLen + 1];
    LPTSTR pMacroValue = NULL;

    LPTSTR pszMacroList[] = {
        TEXT ("MODEL"),
        TEXT ("HARDWAREID"),
    };


    while (ch = *pSrc++) {
        switch (dwState) {
        case NORMALTEXT:
            if (ch == TEXT ('%')) {
                // Start a macro
                dwState = STARTMACRO;
                dwMacroLen = 0;
                szMacroName[0] = 0;
            }
            else {
                if (dwLen >= dwDestLen) {
                    dwLen ++;
                }
                else {
                    pDest[dwLen++] = ch;
                }
            }

            break;
        case STARTMACRO:
            if (ch == TEXT ('%')) {
                szMacroName[dwMacroLen] = 0;
                // Replace Macro
                for (int i = 0; i < sizeof (pszMacroList) / sizeof (pszMacroList[0]); i++) {
                    if (!lstrcmpi (szMacroName, pszMacroList[i])) {

                        pMacroValue = 0;
                        switch (i) {
                        case 0:
                            AssignString (pMacroValue, m_pInfo2->pDriverName);
                            break;
                        case 1:
                            GetDriverData (HardwareID , pMacroValue);
                            break;
                        default:
                            break;
                        }

                        if (pMacroValue) {

                            if (dwDestLen > dwLen)
                                dwAvailbleSize =  dwDestLen - dwLen;
                            else
                                dwAvailbleSize = 0;

                            TCHAR szPlaceHolder[1];
                            DWORD dwBufSize = sizeof (szPlaceHolder) / sizeof (TCHAR);
                            if (!InternetCanonicalizeUrl (pMacroValue, szPlaceHolder, &dwBufSize, 0)) {
                                if (dwBufSize < dwAvailbleSize ) {
                                    if (!InternetCanonicalizeUrl (pMacroValue, pDest + dwLen, &dwBufSize, 0)) {
                                        LocalFree (pMacroValue);
                                        return bRet;
                                    }
                                    else {
                                        dwLen = lstrlen (pDest);
                                    }
                                }
                                else {
                                    dwLen += dwBufSize;
                                }
                            }
                            LocalFree (pMacroValue);
                        }
                        break;
                    }
                }

                dwState = NORMALTEXT;
            }
            else {
                if (dwMacroLen < dwMaxMacroLen) {
                    szMacroName[dwMacroLen ++] = ch;
                }
            }
            break;
        }
    }

    if (dwState == STARTMACRO) {
        SetLastError ( ERROR_INVALID_DATA );
    }
    else {
        if (dwLen >= dwDestLen) {
            SetLastError (ERROR_INSUFFICIENT_BUFFER);
            dwDestLen = dwLen + 1;
        }
        else {
            pDest[dwLen] = 0;
            bRet = TRUE;
        }
    }

    return bRet;

}

LPTSTR CPrinter::GetOemUrl(
    LPTSTR & pszManufacturer)
{
    LPTSTR pszOemUrlPattern = NULL;
    DWORD dwLen = 0;
    LPTSTR pszUrl = NULL;

    if (!GetPrinterInfo2 () )
        goto Cleanup;

    if (GetDriverData (OEMUrlPattern, pszOemUrlPattern)) {

        if (! ParseUrlPattern (pszOemUrlPattern, NULL, dwLen)
            && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

            m_pszOemUrl = (LPTSTR) LocalAlloc (LPTR, sizeof (TCHAR) * dwLen);
            if (m_pszOemUrl) {

                if (!ParseUrlPattern (pszOemUrlPattern, m_pszOemUrl, dwLen))
                    goto Cleanup;
            }
            else
                goto Cleanup;
        }

    }

    if (GetDriverData (Manufacturer, m_pszManufacturer)) {
        pszManufacturer = m_pszManufacturer;
        pszUrl =  m_pszOemUrl;
    }

Cleanup:
    if (pszOemUrlPattern) {
        LocalFree ( pszOemUrlPattern);
    }

    return pszUrl;
}