michaelrsweet / pappl

PAPPL - Printer Application Framework
https://www.msweet.org/pappl
Apache License 2.0
309 stars 49 forks source link

papplPrinterSetDriverData() does not conserve vendor option choices #108

Closed tillkamppeter closed 3 years ago

tillkamppeter commented 3 years ago

Vendor options and their choices are held in the printer->driver_attrs IPP structure, not in the printer->driver_data structure, there only the names of the added IPP attributes are held.

If I call papplPrinterSetDriverData() to save changes in the printer->driver_data the printer->driver_attrs IPP structure is completely deleted and re-made only based on information from the printer->driver_data structure, which DOES NOT contain the types and choices of the vendor options. So the vendor options are lost after calling papplPrinterSetDriverData().

Here is the code of the function:

  // Copy driver data to printer
  memcpy(&printer->driver_data, data, sizeof(printer->driver_data));

  // Create printer (capability) attributes based on driver data...
  ippDelete(printer->driver_attrs);
  printer->driver_attrs = make_attrs(printer->system, &printer->driver_data);

The first line saves the new printer->driver_data structure, the second deletes printer->driver_attrs and the last generates new attributes solely from the printer->driver_data.

michaelrsweet commented 3 years ago

@tillkamppeter The papplPrinterSetDriverData API explicitly resets the attributes. The caller is expected to pass in an ipp_t pointer for any custom/vendor attributes:

Note: This function regenerates all of the driver-specific capability attributes like "media-col-database", "sides-supported", and so forth. Use the papplPrinterSetDriverDefaults or papplPrinterSetReadyMedia functions to efficiently change the "xxx-default" or "xxx-ready" values, respectively.

tillkamppeter commented 3 years ago

I got the "Installable Options" support for the PostScript Printer Application completely working now. The update of the driver data looks a little awkward though as I have to backup and restore the vendor option IPP attributes:

static bool                   // O - `true` on success, `false` on failure
ps_status(
    pappl_printer_t *printer) // I - Printer
{
  int                    i;
  pappl_system_t         *system;       // System (for logging)
  pappl_pr_driver_data_t driver_data;
  ps_driver_extension_t  *extension;
  ipp_t                  *driver_attrs,
                         *vendor_attrs;
  ipp_attribute_t        *attr;
  char                   buf[1024];

  // Get system for logging...
  system = papplPrinterGetSystem(printer);

  papplLog(system, PAPPL_LOGLEVEL_DEBUG,
       "Status callback called for printer %s.",
       papplPrinterGetName(printer));

  // Load the driver data
  papplPrinterGetDriverData(printer, &driver_data);
  driver_attrs = papplPrinterGetDriverAttributes(printer);
  extension = (ps_driver_extension_t *)driver_data.extension;
  if (!extension->updated)
  {
    if ((attr = ippFindAttribute(driver_attrs, "installable-options-default",
                 IPP_TAG_ZERO)) != NULL &&
    ippAttributeString(attr, buf, sizeof(buf)) > 0)
      papplLog(system, PAPPL_LOGLEVEL_DEBUG,
           "Applying installable accessories settings: %s", buf);
    else
      papplLog(system, PAPPL_LOGLEVEL_DEBUG,
           "Installable Options settings not found");

    // Update the driver data to correspond with the printer hardware
    // accessory configuration ("Installable Options" in the PPD)
    ps_driver_setup(system, NULL, NULL, NULL, &driver_data, &driver_attrs,
            NULL);

    // Copy the vendor option IPP attributes
    vendor_attrs = ippNew();
    for (i = 0; i < driver_data.num_vendor; i ++)
    {
      snprintf(buf, sizeof(buf), "%s-default", driver_data.vendor[i]);
      attr = ippFindAttribute(driver_attrs, buf, IPP_TAG_ZERO);
      if (attr)
    ippCopyAttribute(vendor_attrs, attr, 0);
      snprintf(buf, sizeof(buf), "%s-supported", driver_data.vendor[i]);
      attr = ippFindAttribute(driver_attrs, buf, IPP_TAG_ZERO);
      if (attr)
    ippCopyAttribute(vendor_attrs, attr, 0);
    }

    // Save the updated driver data back to the printer
    papplPrinterSetDriverData(printer, &driver_data, NULL);

    // Save the vendor options IPP attributes back into the driver attributes
    driver_attrs = papplPrinterGetDriverAttributes(printer);
    ippCopyAttributes(driver_attrs, vendor_attrs, 0, NULL, NULL);
    ippDelete(vendor_attrs);

    // Save new default settings
    papplSystemSaveState(system, STATE_FILE);
  }

  return (true);
}