/*++

Copyright (c) 1995  Microsoft Corporation

Module Name:

    quryprnt.c

Abstract:

    Implementation of DrvQueryPrint

[Environment:]

    Win32 subsystem, PostScript driver, user mode

Revision History:

    06/22/95 -davidx-
        Ported from Daytona.

    mm/dd/yy -author-
        description

--*/


#include "psui.h"
#include "regdata.h"
#include "..\..\lib\um\dqpfunc.c"


BOOL QueryPrintForm(PDEVQUERYPRINT_INFO, HPPD, PDEVMODE);
BOOL QueryPrinterFeatures(PDEVQUERYPRINT_INFO, HPPD, PSDEVMODE *);



BOOL
DevQueryPrintEx(
    PDEVQUERYPRINT_INFO pDQPInfo
    )

/*++

Routine Description:

    This routine determines whether or not the driver can print the job
    described by pDevMode on the printer described by hPrinter.

Arguments:

    pDQPInfo - Points to a DEVQUERYPRINT_INFO structure

Return Value:

   TRUE if there is no conflict, FALSE otherwise

--*/

{
    HPPD        hppd = NULL;
    PDEVMODE    pdm = NULL;
    INT         errID = 0;
    BOOL        result = TRUE;

    //
    // If no devmode is specified, default will be used
    //

    Assert(pDQPInfo && pDQPInfo->Level >= 1);

    if (pDQPInfo->pDevMode == NULL)
        return TRUE;

    //
    // Load printer description file and verify devmode information
    //

    if ((hppd = LoadPpdFile(pDQPInfo->hPrinter, TRUE)) == NULL) {

        errID = IDS_DQPERR_PPD;

    } if ((pdm = MEMALLOC(sizeof(PSDEVMODE))) == NULL) {

        errID = IDS_DQPERR_MEMORY;

    } else if (!SetDefaultDevMode(pdm, NULL, hppd, IsMetricCountry()) ||
               !ValidateSetDevMode(pdm, pDQPInfo->pDevMode, hppd))
    {
        errID = IDS_INVALID_DEVMODE;

    } else if (!QueryPrintForm(pDQPInfo, hppd, pdm)) {

        result = FALSE;

    } else if (!QueryPrinterFeatures(pDQPInfo, hppd, (PSDEVMODE *) pdm)) {
        
        errID = IDS_FEATURE_CONFLICT;

    } else if (!PpdFindResolution(hppd, pdm->dmPrintQuality) &&
               PpdDefaultResolution(hppd) != pdm->dmPrintQuality)
    {
        errID = IDS_INVALID_RESOLUTION;
    }

    if (result && errID) {

        DQPsprintf(ghInstance,
                   pDQPInfo->pszErrorStr,
                   pDQPInfo->cchErrorStr,
                   &pDQPInfo->cchNeeded,
                   TEXT("%!"),
                   errID);

        result = FALSE;
    }

    //
    // Clean up before returning
    //

    if (hppd)
        UnloadPpdFile(hppd);

    if (pdm)
        MEMFREE(pdm);

    return result;
}



BOOL
QueryPrintForm(
    PDEVQUERYPRINT_INFO pDQPInfo,
    HPPD                hppd,
    PDEVMODE            pDevMode
    )

/*++

Routine Description:

    Verify specified paper/form option is supported by printer

Arguments:

    pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
    hppd - Handle to printer PPD object
    pDevMode - Pointer to DEVMODE data

Return Value:

    TRUE if there is no conflict, FALSE otherwise

--*/

{
    FORM_TRAY_TABLE FormTrayTable;
    LOGFORM         logForm;
    WCHAR           SlotName[MAX_OPTION_NAME];
    BOOL            result = TRUE;
    INT             errID = 0;

    switch (ValidateDevModeForm(pDQPInfo->hPrinter, pDQPInfo->pDevMode, &logForm)) {

    case CUSTOM_FORM:

        //
        // Paper size is specified using paper width and paper length
        //

        if (!FormSupportedOnPrinter(hppd, (PFORM_INFO_1) &logForm, NULL, FALSE))
            errID = IDS_INVALID_CUSTOM_SIZE;
        break;

    case VALID_FORM:

        SlotName[0] = NUL;

        //
        // Check if an input slot is specifically requested
        //

        if ((pDevMode->dmFields & DM_DEFAULTSOURCE) &&
            (pDevMode->dmDefaultSource != DMBIN_FORMSOURCE))
        {
            LONG    SlotNum = (LONG) pDevMode->dmDefaultSource;

            if (SlotNum == DMBIN_MANUAL || SlotNum == DMBIN_ENVMANUAL) {

                //
                // Don't really make sense to assign a form to manual-feed slot
                // Let it through if the paper size is supported on the printer
                // and ignore whatever that's assigned to manual-feed slot.
                //

                if (!FormSupportedOnPrinter(hppd, (PFORM_INFO_1) &logForm, NULL, FALSE))
                    errID = IDS_INVALID_PAPER_SIZE;

                break;

            } else if (hppd->pInputSlots != NULL && SlotNum >= DMBIN_USER) {

                PINPUTSLOT  pInputSlot;

                pInputSlot = (PINPUTSLOT)
                    LISTOBJ_FindIndexed((PLISTOBJ) hppd->pInputSlots->pUiOptions,
                                        SlotNum - DMBIN_USER);

                if (pInputSlot != NULL)
                    CopyStr2Unicode(SlotName, GetXlatedName(pInputSlot), MAX_OPTION_NAME);
            }
        }

        //
        // Retrieve form-to-tray assignment table
        //

        if (FormTrayTable = CurrentFormTrayTable(pDQPInfo->hPrinter)) {

            PWSTR   pNextEntry = FormTrayTable;
            PWSTR   pSlotName, pFormName, pPrinterForm;
            BOOL    IsDefaultTray;

            //
            // Check if there is an entry in the table matching the specified form name
            //

            result = FALSE;

            while (*pNextEntry != NUL) {

                pNextEntry =  EnumFormTrayTable(pNextEntry,
                                                &pSlotName,
                                                &pFormName,
                                                &pPrinterForm,
                                                &IsDefaultTray);

                if (wcscmp(pFormName, logForm.name) == EQUAL_STRING &&
                    (SlotName[0] == NUL || wcscmp(pSlotName, SlotName) == EQUAL_STRING))
                {
                    result = TRUE;
                    break;
                }
            }

            FreeFormTrayTable(FormTrayTable);

            if (!result) {

                WCHAR   formatStr[MAX_OPTION_NAME];

                LoadString(ghInstance, IDS_DQPERR_PAPER_NOT_LOADED, formatStr, MAX_OPTION_NAME);

                DQPsprintf(ghInstance,
                           pDQPInfo->pszErrorStr,
                           pDQPInfo->cchErrorStr,
                           &pDQPInfo->cchNeeded,
                           formatStr,
                           logForm.name,
                           SlotName);
            }
        }

        break;

    default:

        errID = IDS_INVALID_FORM;
        break;
    }

    if (result && errID) {

        DQPsprintf(ghInstance,
                   pDQPInfo->pszErrorStr,
                   pDQPInfo->cchErrorStr,
                   &pDQPInfo->cchNeeded,
                   TEXT("%!"),
                   errID);

        result = FALSE;
    }

    return result;
}



BOOL
QueryPrinterFeatures(
    PDEVQUERYPRINT_INFO pDQPInfo,
    HPPD                hppd,
    PSDEVMODE          *pdm
    )

/*++

Routine Description:

    Look for conflicting printer-feature selections

Arguments:

    pDQPInfo - Points to a DEVQUERYPRINT_INFO structure
    hppd - Handle to PPD object
    pdm - Pointer to a PSDEVMODE structure

Return Value:

    TRUE if there is no conflict, FALSE otherwise

--*/

{
    PPRINTERDATA pPrinterData;
    WORD         index;
    BOOL         result = TRUE;

    //
    // Get printer property data from registry
    //

    if (pPrinterData = GetPrinterProperties(pDQPInfo->hPrinter, hppd)) {
    
        //
        // Convert public devmode fields to printer feature selections
        //
    
        DevModeFieldsToOptions(pdm, pdm->dmPublic.dmFields, hppd);
    
        //
        // Check if any of the doc-sticky features are constrained
        //

        for (index=0; index < hppd->cDocumentStickyFeatures; index++) {
    
            if (PpdFeatureConstrained(hppd,
                                      pPrinterData->options,
                                      pdm->dmPrivate.options,
                                      index,
                                      pdm->dmPrivate.options[index]))
            {
                result = FALSE;
                break;
            }
        }
    
        MEMFREE(pPrinterData);
    }

    return result;
}