CUPS does not support the colord color management framework on Linux #3808

Closed
michaelrsweet opened this Issue Mar 2, 2011 · 25 comments

Comments

Projects
None yet
1 participant
Collaborator

michaelrsweet commented Mar 2, 2011

Version: 1.6-feature
CUPS.org User: hughsient

A daemon called colord[1] now provides a system color management policy service on Linux (not unlike some aspects of ColorSync) which interfaces with the session for settings. GNOME Color Manager currently uses colord to get the policy for display correction on Linux.

Myself and Tim Waugh have been working on CUPS to allow it to register devices and profiles with colord, much like ColorSync.

Till Kamppeter has recently merged my patch to the CUPS ghostscript filters that now query colord for the default ICC profile to use when using Linux. I have sent other patches to Till for the foomatic filter also.

With the attached patch to CUPS, the cupsd daemon adds devices and profiles to colord, which can then have priorities or match rules (we call these 'qualifiers') so that the user can manually assign a manufacturer supplied profile, or even generate a profile themselves using tools like argyllcms.

I've used a local git-svn mirror to generate the patch against svn trunk, although if should apply fine if you use the patch -p1 option.

To test, you need to have colord installed. If colord isn't present then no devices or profiles are added and we continue like normal without errors.

The obvious next step would be to move all the ColorSync-specific code from ipp.c to a new colorsync.c and then call the code in colorsync.c from the new cupsdCmsRegisterPrinter() hooks in printer.c

I could make a patch for this change if required, although it might be better if my patch was merged first from a diffstat size point of view. The current minimal patch also appears to apply against 1.4.

I'm happy to rework the code as required, and can contribute the code under any license required. I'm also happy to maintain the colord specific code if this is required.

Thanks.

Richard Hughes

Collaborator

michaelrsweet commented Mar 12, 2011

CUPS.org User: mike

For CUPS 1.5; Richard, please see my separate email about the CUPS Contributor Agreement we'll need you to sign...

Collaborator

michaelrsweet commented Mar 14, 2011

CUPS.org User: hughsient

Cool, thanks. I'm just running the contribution agreement through the Red Hat legal team. It hopefully won't take too long. Thanks.

Collaborator

michaelrsweet commented May 6, 2011

CUPS.org User: mike

Pushing out pending licensing...

Collaborator

michaelrsweet commented May 16, 2011

CUPS.org User: mike

Some integration notes:

  1. Scope needs to be "disk" to preserve the semantics of the interface we have with ColorSync and to allow for profiles to exist if cupsd is not running (launch-on-demand for future Linux versions of cupsd). That would also eliminate the start/stop calls since we can open a DBUS connection on demand and leave it open for the life of cupsd.
  2. Doesn't seem like there is a provision for profiling of grayscale devices?!?
  3. I don't like calling dbus_send_with_reply_and_block with an indefinite timeout - seems like a denial-of-service attack waiting to happen. We should set a reasonable timeout (5 seconds/5000 milliseconds?) to avoid handling cupsd indefinitely.
  4. The Vendor/Model mapping is wrong.
  5. You don't need to look for APTiogaProfile; that is a very old keyword for "Tioga" drivers on Mac OS X 10.0/10.1 that will never be seen on a Linux system.
  6. Not sure whether the relation should be "hard" or "soft" here.
  7. Should use cupsArrayNew3 for the profiles array which allows you to define "copy" and "free" functions for the elements.
Collaborator

michaelrsweet commented May 17, 2011

CUPS.org User: hughsient

Scope needs to be "disk"...

I'll experiment with this. The reason "temp" was chosen was so that we didn't get "dead" devices listing in the colord UI's -- only connected devices. It's likely that I'll need to add an 'Active' property or something to make a sane UI. When I've done that I'll update the patch on this bug.

Doesn't seem like there is a provision for profiling of grayscale devices?!?

All devices get added an explicit grayscale profile, even if they are "color" devices.

I don't like calling dbus_send_with_reply_and_block with an indefinite timeout...

Fair point, changed.

The Vendor/Model mapping is wrong.

Good catch, I've set the Vendor property from ppd->manufacturer and the Model property from ppd->modelname.

You don't need to look for APTiogaProfile

Good catch, thanks.

Not sure whether the relation should be "hard" or "soft" here.

Certainly soft, only user-defined mappings are defines as hard.

Should use cupsArrayNew3 for the profiles array...

Fixed, thanks.

Collaborator

michaelrsweet commented May 17, 2011

CUPS.org User: hughsient

I've committed this to colord:

commit 8033b6a64c4e9ab0305dff7bd65068386bd05f09
Author: Richard Hughes richard@hughsie.com
Date: Tue May 17 09:16:00 2011 +0100

When creating a device with the same name as an existing virtual device promote it to a physical device

This can happen if a printer is saved and then restored at next boot before the
CUPS daemon is running. In this case we want to make the printer look like a
proper connected device in the client UI.
Collaborator

michaelrsweet commented Aug 11, 2011

CUPS.org User: hughsient

The new patch changes four things:

  • It now sets the colorspace property for the PPD-embedded profile in colord
  • It now sets the device format, so we can more accurately match profiles to devices automatically in a GUI
  • Remote printers are ignored, as the remote printer can't access the local icc file anyway
  • If accessing the system bus fails on Linux (highly unlikely), then we don't crash cupsd.

Richard.

Collaborator

michaelrsweet commented Aug 23, 2011

CUPS.org User: hughsient

I've uploaded the patch with a BSD license on the advice of Richard Fontana. Please let me know if this is okay. Thanks.

Collaborator

michaelrsweet commented Oct 3, 2011

CUPS.org User: hughsient

New version fixes DeleteDevice to actually use an object path, not an object ID, so hot-removing devices DTRT.

Note: We've included versions of this patch in Fedora for 10 months now. It's also being included in the other distributions for a few weeks. It would be great to actually get this upstream.

Thanks,

Richard

Collaborator

michaelrsweet commented May 2, 2012

CUPS.org User: mike

Starting on this next (probably tomorrow) after I finish the last Avahi bits in libcups.

Collaborator

michaelrsweet commented May 21, 2012

CUPS.org User: mike

Attached the initial integration of the supplied code; still needs to be tested. Aside from the usual code and formatting cleanup, I pulled the retry-connection code from the register_printer and unregister_printer functions and made a macro to create the D-Bus messages.

Collaborator

michaelrsweet commented May 21, 2012

CUPS.org User: mike

Wow, one typo in r10491 (missing semicolon). Checking that change in now.

Richard, please test and verify that I haven't messed anything up...

Collaborator

michaelrsweet commented May 22, 2012

CUPS.org User: hughsient

The colord support seems to work well when a device is hotplugged (i.e. USB add) but doesn't seem to work for me when cupsd starts up and does the initial scan for printers, i.e. at coldplug. This could be something on my system if you want me to debug further, but it seems at coldplug time the device isn't registered with colord.

I really appreciate the review and rework, btw. Thanks.

Collaborator

michaelrsweet commented May 22, 2012

CUPS.org User: mike

Ok, I know what the problem is. I forgot to add re-registration of existing queues in cupsdStartColor; this was previously done in cupsdSetPrinterAttrs, but I had removed from there because of performance concerns...

Collaborator

michaelrsweet commented May 23, 2012

CUPS.org User: mike

Richard,

Try TOT or the attached patch - it adds registration of existing printers in cupsdStartColor().

Collaborator

michaelrsweet commented May 23, 2012

CUPS.org User: hughsient

it adds registration of existing printers in cupsdStartColor

svn head now works beautifully, many thanks.

Collaborator

michaelrsweet commented May 23, 2012

CUPS.org User: mike

Perfect, thanks for testing!

Collaborator

michaelrsweet commented May 23, 2012

"0001-Add-colord-support-to-CUPS-which-allows-Linux-printe.patch":

From 748f52e2fc550b48a622b14b57caf8ab0e283459 Mon Sep 17 00:00:00 2001
From: Richard Hughes richard@hughsie.com
Date: Tue, 1 Mar 2011 16:05:48 +0000
Subject: [PATCH] Add colord support to CUPS which allows Linux printers to be color managed


scheduler/Makefile | 1 +
scheduler/colord.c | 678 ++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/colord.h | 22 ++
scheduler/ipp.c | 18 ++-
scheduler/printers.c | 69 +++++
scheduler/printers.h | 4 +
6 files changed, 789 insertions(+), 3 deletions(-)
create mode 100644 scheduler/colord.c
create mode 100644 scheduler/colord.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 0decf8f..a35ee82 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -26,6 +26,7 @@ CUPSDOBJS =
env.o
main.o
ipp.o \

  •   colord.o \
    listen.o \
    job.o \
    log.o \
    
    diff --git a/scheduler/colord.c b/scheduler/colord.c
    new file mode 100644
    index 0000000..60ee415
    --- /dev/null
    +++ b/scheduler/colord.c
    @@ -0,0 +1,678 @@
    +/*
  • * "$Id$"
  • * colord integration for the CUPS scheduler.
  • * Copyright 2011, Red Hat.
  • * These coded instructions, statements, and computer programs are the
  • * property of Apple Inc. and are protected by Federal copyright
  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"
  • * which should have been included with this file. If this file is
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • * Contents:
  • * colordRegisterPrinter() - Register profiles for a printer.
  • * colordUnregisterPrinter() - Unregister profiles for a printer.
  • * colordStart() - Get a connection to the system bus.
  • * colordStop() - Release any connection to the system bus
  • * so that added profiles and devices are
  • * automatically removed.
  • /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#ifdef HAVE_DBUS
    +
    +#include <dbus/dbus.h>
    +#include <cups/ppd-private.h>
    +
    +/
  • * Defines used by colord. See the reference docs for futher details:
  • * http://colord.hughsie.com/api/ref-dbus.html
  • /
    +#define COLORD_SCOPE_NORMAL "normal" /
    System scope /
    +#define COLORD_SCOPE_TEMP "temp" /
    Process scope /
    +#define COLORD_SCOPE_DISK "disk" /
    Lives forever, as stored in DB /
    +
    +#define COLORD_RELATION_SOFT "soft" /
    Mapping is not default /
    +#define COLORD_RELATION_HARD "hard" /
    Explicitly mapped profile /
    +
    +#define COLORD_SPACE_RGB "rgb" /
    RGB colorspace /
    +#define COLORD_SPACE_CMYK "cmyk" /
    CMYK colorspace /
    +
    +#define COLORD_MODE_PHYSICAL "physical" /
    Actual device /
    +#define COLORD_MODE_VIRTUAL "virtual" /
    Virtual device with no hardware /
    +
    +#define COLORD_KIND_PRINTER "printer" /
    printing output device /
    +
    +/
    This is static /
    +static DBusConnection *con = NULL;
    +
    +/
  • * 'colordStart()' - Get a connection to the system bus.
  • */
    +
    +void
    +colordStart(void)
    +{
  • if (con)
  • return;
  • con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
    +}

+/*

  • * 'colordStop()' - Release any connection to the system bus so that
  • * added profiles and devices are automatically removed.
  • */
    +
    +void
    +colordStop(void)
    +{
  • if (con == NULL)
  • return;
  • dbus_connection_unref(con);
  • con = NULL;
    +}

+/*

  • * 'message_dict_add_strings()' - add two strings to a dictionary.
  • */
    +
    +static void
    +message_dict_add_strings (DBusMessageIter *dict,
  •                      const char *key,
    
  •                      const char *value)
    
    +{
  •    DBusMessageIter entry;
    
  •    dbus_message_iter_open_container(dict,
    
  •                                     DBUS_TYPE_DICT_ENTRY,
    
  •                                     NULL,
    
  •                                     &entry);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
    
  •    dbus_message_iter_close_container(dict, &entry);
    
    +}
    +
    +/*
  • * 'colordCreateProfile()' - Create a color profile for a printer.
  • * Notes: When creating the device, we can create
  • /
    +
    +static void
    +colordCreateProfile (cups_array_t *profiles, /
    I - Profiles array */
  •                 const char _printer_name,  /_ I - Printer name */
    
  •                 const char _qualifier,     /_ I - Profile qualifier */
    
  •                 const char _iccfile,       /_ I - ICC filename */
    
  •                 const char _scope)         /_ I - The scope of the profile, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • int options = 1; /* Options for CreateDevice */
  • char idstr; / Profile ID string */
  • size_t idstrlen; /* Profile ID allocated length */
  • const char profile_path; / Device object path */
  • /*
  • * Create the profile...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateProfile");
    
  • /* create a profile id */
  • idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1;
  • idstr = malloc (idstrlen);
  • if (!idstr)
  •  goto out;
    
  • snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile id of %s",
  •              idstr);
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                               DBUS_TYPE_ARRAY,
    
  •                               "{ss}",
    
  •                               &dict);
    
  • message_dict_add_strings(&dict, "Qualifier", qualifier);
  • if (iccfile != NULL)
  • message_dict_add_strings(&dict, "Filename", iccfile);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%d)",
  •              idstr, options);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created profile %s",
    
  •              profile_path);
    
  • cupsArrayAdd(profiles, strdup(profile_path));

+out:

  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • free (idstr);
    +}

+/*

  • * 'colordDeviceAddProfile()' - Assign a profile to a device.
  • /
    +
    +static void
    +colordDeviceAddProfile (const char *device_path, /
    I - Device object path */
  •                    const char _profile_path,      /_ I - Profile object path */
    
  •                    const char _relation)          /_ I - Device relation, either 'soft' or 'hard' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     device_path,
    
  •                                     "org.freedesktop.ColorManager.Device",
    
  •                                     "AddProfile");
    
  • /* send profile path as the argument */
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "Calling %s:AddProfile(%s) [%s]",
    
  •              device_path, profile_path, relation);
    
  • /* send syncronous */
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to AddProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordCreateDevice()' - Create a device and register profiles.
  • /
    +
    +static void
    +colordCreateDevice (cupsd_printer_t *p, /
    I - Printer */
  •                cups_array_t _profiles,     /_ I - Profiles array */
    
  •                const char _colorspace,     /_ I - Device colorspace, e.g. 'rgb' */
    
  •                const char _relation,       /_ I - Profile relation, either 'soft' or 'hard' */
    
  •                const char _scope)          /_ I - The scope of the device, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path; / Device object path */
  • const char profile_path; / Profile path */
  • char *default_profile_path = NULL;
  •                                            /\* Default profile path */
    
  • /*
  • * Create the device...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &p->name);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                             DBUS_TYPE_ARRAY,
    
  •                             "{ss}",
    
  •                             &dict);
    
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • message_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
  • message_dict_add_strings(&dict, "Vendor", p->make_model);
  • message_dict_add_strings(&dict, "Model", p->name);
  • message_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
  • message_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)",
  •              p->name, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created device %s",
    
  •              device_path);
    
  • /* add profiles */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path;
    
  •   profile_path = cupsArrayNext(profiles))
    
  • {
  • colordDeviceAddProfile (device_path, profile_path, relation);
  • }

+out:

  • free(default_profile_path);
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordDeleteDevice()' - Delete a device
  • /
    +
    +static void
    +colordDeleteDevice (const char *device_id) /
    I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • /*
  • * Create the device...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "DeleteDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordDeleteProfilesForDevice()' - Delete previously registered
  • * color device and profiles
  • /
    +
    +static void
    +colordDeleteProfilesForDevice(const char *device_path) /
    I - D-Bus object path */
    +{
  • const char options = ""; / Options for GetProfilesForDevice */
  • char profile_path; / Profile path */
  • DBusMessage message; / D-Bus message */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusError error; /* D-Bus error */
  • DBusMessageIter args, array_args; /* D-Bus method arguments */
  • /*
  • * Get the profiles
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "GetProfilesForDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &device_path);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &options);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling GetProfilesForDevice(%s,"")",
  •              device_path);
    
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to GetProfilesForDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • /* unwrap the array */
  • dbus_message_iter_init(message, &args);
  • dbus_message_iter_recurse(&args, &array_args);
  • do
  • {
  • if (dbus_message_iter_get_arg_type(&array_args) == DBUS_TYPE_OBJECT_PATH)
  • {
  •  dbus_message_iter_get_basic(&array_args, &profile_path);
    
  •  /*
    
  •   \* Delete each profile.
    
  •   */
    
  •  cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                  "need to delete %s (?)",
    
  •                  profile_path);
    
  • }
  • } while (dbus_message_iter_next(&array_args));
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordRegisterPrinter()' - Register profiles for a printer.
  • /
    +
    +void
    +colordRegisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char ppdfile[1024], /* PPD filename */
  •                    iccfile[1024];  /\* ICC filename */
    
  • ppd_file_t ppd; / PPD file */
  • char profile_path; / Profile path */
  • cups_array_t profiles; / Profile paths array */
  • const char profile_key; / Profile keyword */
  • ppd_attr_t attr; / Profile attributes */
  • const char device_colorspace; / Device colorspace */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • /*
  • * Try opening the PPD file for this printer...
  • */
  • snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
  • if ((ppd = ppdOpenFile(ppdfile)) == NULL)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN,
  •                "cannot open %s",
    
  •                ppdfile);
    
  • return;
  • }
  • /*
  • * See if we have any embedded profiles...
  • */
  • profiles = cupsArrayNew (NULL, NULL);
  • profile_key = "APTiogaProfile";
  • attr = ppdFindAttr(ppd, "profile_key", NULL);
  • if (attr == NULL)
  • {
  • profile_key = "cupsICCProfile";
  • attr = ppdFindAttr(ppd, profile_key, NULL);
  • }
  • for (; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
  • if (attr->spec[0] && attr->value && attr->value[0])
  • {
  •  if (attr->value[0] != '/')
    
  •    snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
    
  •             attr->value);
    
  •  else
    
  •    strlcpy(iccfile, attr->value, sizeof(iccfile));
    
  •  if (access(iccfile, 0))
    
  •  {
    
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "no access to %s",
    
  •                    iccfile);
    
  •    continue;
    
  •  }
    
  •  colordCreateProfile(profiles,
    
  •                      p->name,
    
  •                      attr->spec,
    
  •                      iccfile,
    
  •                      COLORD_SCOPE_TEMP);
    
  • }
  • /*
  • * Add the grayscale profile first. We always have a grayscale profile.
  • */
  • colordCreateProfile(profiles,
  •                  p->name,
    
  •                  "Gray..",
    
  •                  NULL,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Then add the RGB/CMYK/DeviceN color profile...
  • */
  • device_colorspace = "unknown";
  • switch (ppd->colorspace)
  • {
  • case PPD_CS_RGB :
  • case PPD_CS_CMY :
  •    device_colorspace = COLORD_SPACE_RGB;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "RGB..",
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_RGBK :
  • case PPD_CS_CMYK :
  •    device_colorspace = COLORD_SPACE_CMYK;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "CMYK..",
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_GRAY :
  •    if (attr)
    
  •      break;
    
  • case PPD_CS_N :
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "DeviceN..",
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • }
  • /*
  • * Register the device with colord.
  • */
  • cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for "%s"",
  •              p->name);
    
  • colordCreateDevice (p,
  •                  profiles,
    
  •                  device_colorspace,
    
  •                  COLORD_RELATION_SOFT,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Free any memory we used...
  • */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path != NULL;
    
  •   profile_path = cupsArrayNext(profiles)) {
    
  • free(profile_path);
  • }
  • cupsArrayDelete(profiles);
  • ppdClose(ppd);
    +}

+/*

  • * 'colordUnregisterPrinter()' - Unregister profiles for a printer.
  • /
    +
    +void
    +colordUnregisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • const char device_path; / Device path */
  • DBusError error; /* D-Bus error */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessage message; / D-Bus message */
  • DBusMessage reply = NULL; / D-Bus reply */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • /*
  • * Get the device path
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "FindDeviceById");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &p->name);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById");
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to FindDeviceById: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • /* delete profiles for the device */
  • colordDeleteProfilesForDevice (device_path);
  • /* delete the device itself */
  • colordDeleteDevice(p->name);

+out:

  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • dbus_connection_unref(con);
    +}

+#endif /* HAVE_DBUS /
+
+/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/colord.h b/scheduler/colord.h
    new file mode 100644
    index 0000000..262b695
    --- /dev/null
    +++ b/scheduler/colord.h
    @@ -0,0 +1,22 @@
    +/

  • * "$Id$"

  • * colord integration for the CUPS scheduler.

  • * Copyright 2011, Red Hat.

  • * These coded instructions, statements, and computer programs are the

  • * property of Apple Inc. and are protected by Federal copyright

  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"

  • * which should have been included with this file. If this file is

  • * file is missing or damaged, see the license at "http://www.cups.org/".

  • /
    +
    +void colordRegisterPrinter(cupsd_printer_t *p);
    +void colordUnregisterPrinter(cupsd_printer_t *p);
    +void colordStart(void);
    +void colordStop(void);
    +
    +/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/ipp.c b/scheduler/ipp.c
    index 6ba8339..55b7ed3 100644
    --- a/scheduler/ipp.c
    +++ b/scheduler/ipp.c
    @@ -2962,17 +2962,23 @@ add_printer(cupsd_client_t *con, /
    I - Client connection */

    cupsdSetPrinterReasons(printer, "none");

-#ifdef APPLE
/*
* (Re)register color profiles...
*/

 if (!RunUser)
 {
  •  cupsdCmsRegisterPrinter(printer);
    
    +#ifdef APPLE
  • /*
    
  •  \* FIXME: ideally the ColorSync stuff would be moved to colorsync.c
    
  •  \* and the colorsyncRegisterProfiles() would be called from
    
  •  \* cupsdCmsRegisterPrinter() in printers.c
    
  •  */
    
    apple_unregister_profiles(printer);
    apple_register_profiles(printer);
  • }
    #endif /* APPLE */
  • }
    }

/*
@@ -7052,11 +7058,17 @@ delete_printer(cupsd_client_t con, / I - Client connection */
snprintf(filename, sizeof(filename), "%s/%s.pwg3", CacheDir, printer->name);
unlink(filename);

-#ifdef APPLE
/*

  • Unregister color profiles...
    */
  • cupsdCmsUnregisterPrinter(printer);
    +#ifdef APPLE
  • /*
  • * FIXME: ideally the ColorSync stuff would be moved to colorsync.c
  • * and the colorsyncUnregisterPrinter() would be called from
  • * cupsdCmsUnregisterPrinter() in printers.c
  • /
    apple_unregister_profiles(printer);
    #endif /
    APPLE */

diff --git a/scheduler/printers.c b/scheduler/printers.c
index 71c24bf..b0a7c63 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -80,6 +80,9 @@

include <sys/vfs.h>

#endif /* HAVE_SYS_VFS_H */

+#ifdef HAVE_DBUS
+# include "colord.h"
+#endif /* HAVE_DBUS */

/*

  • Local functions...
    @@ -740,6 +743,53 @@ cupsdDeleteAllPrinters(void)
    }
    }

+/*

  • * 'cupsdCmsRegisterPrinter()' - Registers a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsRegisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordRegisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsUnregisterPrinter()' - Unregisters a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsUnregisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordUnregisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStart()' - Starts the CMS
  • */
    +
    +void
    +cupsdCmsStart(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStart();
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStop()' - Stops the CMS
  • */
    +
    +void
    +cupsdCmsStop(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStop();
    +#endif /* defined(HAVE_DBUS) */
    +}

/*

  • 'cupsdDeletePrinter()' - Delete a printer from the system.
    @@ -780,6 +830,12 @@ cupsdDeletePrinter(
    "Job stopped.");

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • If this printer is the next for browsing, point to the next one...
      */

@@ -1488,6 +1544,12 @@ cupsdRenamePrinter(
p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • Rename the printer...
      */

@@ -2700,6 +2762,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t p)/ I - Printer to setup /
#endif /
__sgi */

/*

  • * Re-register profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • cupsdCmsRegisterPrinter(p);
  • /*
    • Let the browse protocols reflect the change
      */

diff --git a/scheduler/printers.h b/scheduler/printers.h
index 3afc88d..85d2c88 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -175,6 +175,10 @@ extern const char _cupsdValidateDest(const char *uri,
cups_ptype_t *dtype,
cupsd_printer_t *_printer);
extern void cupsdWritePrintcap(void);
+extern void cupsdCmsRegisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsUnregisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsStart(void);
+extern void cupsdCmsStop(void);

/*

1.7.4.1

Collaborator

michaelrsweet commented May 23, 2012

"0001-Add-colord-support-to-CUPS-which-allows-Linux-printe_v2.patch":

From 473d63e13b6681af66c2f34c9f8d8bbda0ed8964 Mon Sep 17 00:00:00 2001
From: Richard Hughes richard@hughsie.com
Date: Tue, 1 Mar 2011 16:05:48 +0000
Subject: [PATCH] Add colord support to CUPS which allows Linux printers to be color managed


scheduler/Makefile | 1 +
scheduler/colord.c | 665 ++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/colord.h | 22 ++
scheduler/ipp.c | 18 ++-
scheduler/printers.c | 69 ++++++
scheduler/printers.h | 4 +
6 files changed, 776 insertions(+), 3 deletions(-)
create mode 100644 scheduler/colord.c
create mode 100644 scheduler/colord.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 0decf8f..a35ee82 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -26,6 +26,7 @@ CUPSDOBJS =
env.o
main.o
ipp.o \

  •   colord.o \
    listen.o \
    job.o \
    log.o \
    
    diff --git a/scheduler/colord.c b/scheduler/colord.c
    new file mode 100644
    index 0000000..2fdf401
    --- /dev/null
    +++ b/scheduler/colord.c
    @@ -0,0 +1,665 @@
    +/*
  • * "$Id$"
  • * colord integration for the CUPS scheduler.
  • * Copyright 2011, Red Hat.
  • * These coded instructions, statements, and computer programs are the
  • * property of Apple Inc. and are protected by Federal copyright
  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"
  • * which should have been included with this file. If this file is
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • * Contents:
  • * colordRegisterPrinter() - Register profiles for a printer.
  • * colordUnregisterPrinter() - Unregister profiles for a printer.
  • * colordStart() - Get a connection to the system bus.
  • * colordStop() - Release any connection to the system bus
  • * so that added profiles and devices are
  • * automatically removed.
  • /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#ifdef HAVE_DBUS
    +
    +#include <dbus/dbus.h>
    +#include <cups/ppd-private.h>
    +
    +/
  • * Defines used by colord. See the reference docs for further details:
  • * http://colord.hughsie.com/api/ref-dbus.html
  • /
    +#define COLORD_SCOPE_NORMAL "normal" /
    System scope /
    +#define COLORD_SCOPE_TEMP "temp" /
    Process scope /
    +#define COLORD_SCOPE_DISK "disk" /
    Lives forever, as stored in DB /
    +
    +#define COLORD_RELATION_SOFT "soft" /
    Mapping is not default /
    +#define COLORD_RELATION_HARD "hard" /
    Explicitly mapped profile /
    +
    +#define COLORD_SPACE_RGB "rgb" /
    RGB colorspace /
    +#define COLORD_SPACE_CMYK "cmyk" /
    CMYK colorspace /
    +
    +#define COLORD_MODE_PHYSICAL "physical" /
    Actual device /
    +#define COLORD_MODE_VIRTUAL "virtual" /
    Virtual device with no hardware /
    +
    +#define COLORD_KIND_PRINTER "printer" /
    printing output device /
    +
    +/
    This is static /
    +static DBusConnection *con = NULL;
    +
    +/
  • * 'colordStart()' - Get a connection to the system bus.
  • */
    +
    +void
    +colordStart(void)
    +{
  • if (con)
  • return;
  • con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
    +}

+/*

  • * 'colordStop()' - Release any connection to the system bus so that
  • * added profiles and devices are automatically removed.
  • */
    +
    +void
    +colordStop(void)
    +{
  • if (con == NULL)
  • return;
  • dbus_connection_unref(con);
  • con = NULL;
    +}

+/*

  • * 'message_dict_add_strings()' - add two strings to a dictionary.
  • */
    +
    +static void
    +message_dict_add_strings (DBusMessageIter *dict,
  •                      const char *key,
    
  •                      const char *value)
    
    +{
  •    DBusMessageIter entry;
    
  •    dbus_message_iter_open_container(dict,
    
  •                                     DBUS_TYPE_DICT_ENTRY,
    
  •                                     NULL,
    
  •                                     &entry);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
    
  •    dbus_message_iter_close_container(dict, &entry);
    
    +}
    +
    +/*
  • * 'colordCreateProfile()' - Create a color profile for a printer.
  • * Notes: When creating the device, we can create
  • /
    +
    +static void
    +colordCreateProfile (cups_array_t *profiles, /
    I - Profiles array */
  •                 const char _printer_name,  /_ I - Printer name */
    
  •                 const char _qualifier,     /_ I - Profile qualifier */
    
  •                 const char *_format,       /_ I - Profile qualifier format */
    
  •                 const char _iccfile,       /_ I - ICC filename */
    
  •                 const char _scope)         /_ I - The scope of the profile, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • int options = 1; /* Options for CreateDevice */
  • char idstr; / Profile ID string */
  • size_t idstrlen; /* Profile ID allocated length */
  • const char profile_path; / Device object path */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the profile...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateProfile");
    
  • /* create a profile id */
  • idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1;
  • idstr = malloc (idstrlen);
  • if (!idstr)
  •  goto out;
    
  • snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile id of %s",
  •              idstr);
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                               DBUS_TYPE_ARRAY,
    
  •                               "{ss}",
    
  •                               &dict);
    
  • message_dict_add_strings(&dict, "Qualifier", qualifier);
  • message_dict_add_strings(&dict, "Format", format_str);
  • if (iccfile != NULL)
  • message_dict_add_strings(&dict, "Filename", iccfile);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%d)",
  •              idstr, options);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created profile %s",
    
  •              profile_path);
    
  • cupsArrayAdd(profiles, strdup(profile_path));

+out:

  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • free (idstr);
    +}

+/*

  • * 'colordDeviceAddProfile()' - Assign a profile to a device.
  • /
    +
    +static void
    +colordDeviceAddProfile (const char *device_path, /
    I - Device object path */
  •                    const char _profile_path,      /_ I - Profile object path */
    
  •                    const char _relation)          /_ I - Device relation, either 'soft' or 'hard' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     device_path,
    
  •                                     "org.freedesktop.ColorManager.Device",
    
  •                                     "AddProfile");
    
  • /* send profile path as the argument */
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "Calling %s:AddProfile(%s) [%s]",
    
  •              device_path, profile_path, relation);
    
  • /* send syncronous */
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to AddProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordCreateDevice()' - Create a device and register profiles.
  • /
    +
    +static void
    +colordCreateDevice (cupsd_printer_t *p, /
    I - Printer */
  •                cups_array_t _profiles,     /_ I - Profiles array */
    
  •                const char _colorspace,     /_ I - Device colorspace, e.g. 'rgb' */
    
  •                const char _relation,       /_ I - Profile relation, either 'soft' or 'hard' */
    
  •                const char _scope)          /_ I - The scope of the device, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path; / Device object path */
  • const char profile_path; / Profile path */
  • char *default_profile_path = NULL;
  •                                            /\* Default profile path */
    
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Create the device...
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • device_path = device_id;
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                             DBUS_TYPE_ARRAY,
    
  •                             "{ss}",
    
  •                             &dict);
    
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • message_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
  • if (p->make_model != NULL)
  • message_dict_add_strings(&dict, "Vendor", p->make_model);
  • message_dict_add_strings(&dict, "Model", p->name);
  • if (p->sanitized_device_uri != NULL)
  • message_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
  • message_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)",
  •              device_id, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created device %s",
    
  •              device_path);
    
  • /* add profiles */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path;
    
  •   profile_path = cupsArrayNext(profiles))
    
  • {
  • colordDeviceAddProfile (device_path, profile_path, relation);
  • }

+out:

  • free(default_profile_path);
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordDeleteDevice()' - Delete a device
  • /
    +
    +static void
    +colordDeleteDevice (const char *device_id) /
    I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • /*
  • * Create the device...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "DeleteDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                -1,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordGetQualifierFormat()' - Get the qualifier format.
  • * Notes: Returns a value of "ColorSpace.MediaType.Resolution" by default
  • /
    +
    +char *

    +colordGetQualifierFormat(ppd_file_t *ppd)
    +{
  • char *format; / Qualifier format tuple */
  • const char tmp; / Temporary string */
  • ppd_attr_t attr; / Profile attributes */
  • /* create 3-tuple */
  • format = calloc(3, sizeof(char*));
  • /* get 1st section */
  • tmp = "cupsICCQualifier1";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultColorSpace";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "DefaultColorModel";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[0] = strdup(tmp);
  • /* get 2st section */
  • tmp = "cupsICCQualifier2";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultMediaType";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[1] = strdup(tmp);
  • /* get 3st section */
  • tmp = "cupsICCQualifier3";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultResolution";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[2] = strdup(tmp);
  • return format;
    +}

+/*

  • * 'colordRegisterPrinter()' - Register profiles for a printer.
  • /
    +
    +void
    +colordRegisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char ppdfile[1024], /* PPD filename */
  •                    iccfile[1024];  /\* ICC filename */
    
  • ppd_file_t ppd; / PPD file */
  • char profile_path; / Profile path */
  • cups_array_t profiles; / Profile paths array */
  • const char profile_key; / Profile keyword */
  • ppd_attr_t attr; / Profile attributes */
  • const char device_colorspace; / Device colorspace */
  • char *format; / Qualifier format tuple */
  • int i; /* Loop counter */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • /*
  • * Try opening the PPD file for this printer...
  • */
  • snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
  • if ((ppd = ppdOpenFile(ppdfile)) == NULL)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN,
  •                "cannot open %s",
    
  •                ppdfile);
    
  • return;
  • }
  • /*
  • * Find out the qualifier format
  • */
  • format = colordGetQualifierFormat(ppd);
  • /*
  • * See if we have any embedded profiles...
  • */
  • profiles = cupsArrayNew (NULL, NULL);
  • profile_key = "APTiogaProfile";
  • attr = ppdFindAttr(ppd, profile_key, NULL);
  • if (attr == NULL)
  • {
  • profile_key = "cupsICCProfile";
  • attr = ppdFindAttr(ppd, profile_key, NULL);
  • }
  • for (; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
  • if (attr->spec[0] && attr->value && attr->value[0])
  • {
  •  if (attr->value[0] != '/')
    
  •    snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
    
  •             attr->value);
    
  •  else
    
  •    strlcpy(iccfile, attr->value, sizeof(iccfile));
    
  •  if (access(iccfile, 0))
    
  •  {
    
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "no access to %s",
    
  •                    iccfile);
    
  •    continue;
    
  •  }
    
  •  colordCreateProfile(profiles,
    
  •                      p->name,
    
  •                      attr->spec,
    
  •                      (const char **)format,
    
  •                      iccfile,
    
  •                      COLORD_SCOPE_TEMP);
    
  • }
  • /*
  • * Add the grayscale profile first. We always have a grayscale profile.
  • */
  • colordCreateProfile(profiles,
  •                  p->name,
    
  •                  "Gray..",
    
  •                  (const char **)format,
    
  •                  NULL,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Then add the RGB/CMYK/DeviceN color profile...
  • */
  • device_colorspace = "unknown";
  • switch (ppd->colorspace)
  • {
  • case PPD_CS_RGB :
  • case PPD_CS_CMY :
  •    device_colorspace = COLORD_SPACE_RGB;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "RGB..",
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_RGBK :
  • case PPD_CS_CMYK :
  •    device_colorspace = COLORD_SPACE_CMYK;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "CMYK..",
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_GRAY :
  •    if (attr)
    
  •      break;
    
  • case PPD_CS_N :
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "DeviceN..",
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • }
  • /*
  • * Register the device with colord.
  • */
  • cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for "%s"",
  •              p->name);
    
  • colordCreateDevice (p,
  •                  profiles,
    
  •                  device_colorspace,
    
  •                  COLORD_RELATION_SOFT,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Free any memory we used...
  • */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path != NULL;
    
  •   profile_path = cupsArrayNext(profiles)) {
    
  • free(profile_path);
  • }
  • cupsArrayDelete(profiles);
  • for (i=0; i<3; i++)
  • free(format[i]);
  • free(format);
  • ppdClose(ppd);
    +}

+/*

  • * 'colordUnregisterPrinter()' - Unregister profiles for a printer.
  • /
    +
    +void
    +colordUnregisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • /*
  • * Just delete the device itself, and leave the profiles registered
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • colordDeleteDevice(device_id);
    +}

+#endif /* HAVE_DBUS /
+
+/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/colord.h b/scheduler/colord.h
    new file mode 100644
    index 0000000..262b695
    --- /dev/null
    +++ b/scheduler/colord.h
    @@ -0,0 +1,22 @@
    +/

  • * "$Id$"

  • * colord integration for the CUPS scheduler.

  • * Copyright 2011, Red Hat.

  • * These coded instructions, statements, and computer programs are the

  • * property of Apple Inc. and are protected by Federal copyright

  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"

  • * which should have been included with this file. If this file is

  • * file is missing or damaged, see the license at "http://www.cups.org/".

  • /
    +
    +void colordRegisterPrinter(cupsd_printer_t *p);
    +void colordUnregisterPrinter(cupsd_printer_t *p);
    +void colordStart(void);
    +void colordStop(void);
    +
    +/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/ipp.c b/scheduler/ipp.c
    index 4449392..0f1eeda 100644
    --- a/scheduler/ipp.c
    +++ b/scheduler/ipp.c
    @@ -2954,17 +2954,23 @@ add_printer(cupsd_client_t *con, /
    I - Client connection */

    cupsdSetPrinterReasons(printer, "none");

-#ifdef APPLE
/*
* (Re)register color profiles...
*/

 if (!RunUser)
 {
  •  cupsdCmsRegisterPrinter(printer);
    
    +#ifdef APPLE
  • /*
    
  •  \* FIXME: ideally the ColorSync stuff would be moved to colorsync.c
    
  •  \* and the colorsyncRegisterProfiles() would be called from
    
  •  \* cupsdCmsRegisterPrinter() in printers.c
    
  •  */
    
    apple_unregister_profiles(printer);
    apple_register_profiles(printer);
  • }
    #endif /* APPLE */
  • }
    }

/*
@@ -7023,11 +7029,17 @@ delete_printer(cupsd_client_t con, / I - Client connection */
snprintf(filename, sizeof(filename), "%s/%s.pwg3", CacheDir, printer->name);
unlink(filename);

-#ifdef APPLE
/*

  • Unregister color profiles...
    */
  • cupsdCmsUnregisterPrinter(printer);
    +#ifdef APPLE
  • /*
  • * FIXME: ideally the ColorSync stuff would be moved to colorsync.c
  • * and the colorsyncUnregisterPrinter() would be called from
  • * cupsdCmsUnregisterPrinter() in printers.c
  • /
    apple_unregister_profiles(printer);
    #endif /
    APPLE */

diff --git a/scheduler/printers.c b/scheduler/printers.c
index 696b98d..165e6ab 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -79,6 +79,9 @@

include <sys/vfs.h>

#endif /* HAVE_SYS_VFS_H */

+#ifdef HAVE_DBUS
+# include "colord.h"
+#endif /* HAVE_DBUS */

/*

  • Local functions...
    @@ -675,6 +678,53 @@ cupsdDeleteAllPrinters(void)
    }
    }

+/*

  • * 'cupsdCmsRegisterPrinter()' - Registers a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsRegisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordRegisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsUnregisterPrinter()' - Unregisters a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsUnregisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordUnregisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStart()' - Starts the CMS
  • */
    +
    +void
    +cupsdCmsStart(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStart();
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStop()' - Stops the CMS
  • */
    +
    +void
    +cupsdCmsStop(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStop();
    +#endif /* defined(HAVE_DBUS) */
    +}

/*

  • 'cupsdDeletePrinter()' - Delete a printer from the system.
    @@ -715,6 +765,12 @@ cupsdDeletePrinter(
    "Job stopped.");

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • If this printer is the next for browsing, point to the next one...
      */

@@ -1414,6 +1470,12 @@ cupsdRenamePrinter(
p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • Rename the printer...
      */

@@ -2626,6 +2688,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t p)/ I - Printer to setup /
#endif /
__sgi */

/*

  • * Re-register profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • cupsdCmsRegisterPrinter(p);
  • /*
    • Let the browse protocols reflect the change
      */

diff --git a/scheduler/printers.h b/scheduler/printers.h
index c0db344..572fde7 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -172,6 +172,10 @@ extern const char _cupsdValidateDest(const char *uri,
cups_ptype_t *dtype,
cupsd_printer_t *_printer);
extern void cupsdWritePrintcap(void);
+extern void cupsdCmsRegisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsUnregisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsStart(void);
+extern void cupsdCmsStop(void);

/*

1.7.4.1

Collaborator

michaelrsweet commented May 23, 2012

"0001-Add-colord-support-to-CUPS-which-allows-Linux-printe_v3.patch":

From dda7106a7a40191704545b3fa2f88b6207aad2f5 Mon Sep 17 00:00:00 2001
From: Richard Hughes richard@hughsie.com
Date: Tue, 1 Mar 2011 16:05:48 +0000
Subject: [PATCH] Add colord support to CUPS which allows Linux printers to be
color managed


scheduler/Makefile | 1 +
scheduler/colord.c | 662 ++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/colord.h | 22 ++
scheduler/ipp.c | 18 ++-
scheduler/printers.c | 69 ++++++
scheduler/printers.h | 4 +
6 files changed, 773 insertions(+), 3 deletions(-)
create mode 100644 scheduler/colord.c
create mode 100644 scheduler/colord.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 3c7da8e..b9c47d3 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -27,6 +27,7 @@ CUPSDOBJS =
file.o
main.o
ipp.o \

  •   colord.o \
    listen.o \
    job.o \
    log.o \
    
    diff --git a/scheduler/colord.c b/scheduler/colord.c
    new file mode 100644
    index 0000000..7428bf7
    --- /dev/null
    +++ b/scheduler/colord.c
    @@ -0,0 +1,662 @@
    +/*
  • * "$Id$"
  • * colord integration for the CUPS scheduler.
  • * Copyright 2011, Red Hat.
  • * These coded instructions, statements, and computer programs are the
  • * property of Apple Inc. and are protected by Federal copyright
  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"
  • * which should have been included with this file. If this file is
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • * Contents:
  • * colordRegisterPrinter() - Register profiles for a printer.
  • * colordUnregisterPrinter() - Unregister profiles for a printer.
  • * colordStart() - Get a connection to the system bus.
  • * colordStop() - Release any connection to the system bus
  • * so that added profiles and devices are
  • * automatically removed.
  • /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#ifdef HAVE_DBUS
    +
    +#include <dbus/dbus.h>
    +#include <cups/ppd-private.h>
    +
    +/
  • * Defines used by colord. See the reference docs for further details:
  • * http://colord.hughsie.com/api/ref-dbus.html
  • /
    +#define COLORD_SCOPE_NORMAL "normal" /
    System scope /
    +#define COLORD_SCOPE_TEMP "temp" /
    Process scope /
    +#define COLORD_SCOPE_DISK "disk" /
    Lives forever, as stored in DB /
    +
    +#define COLORD_RELATION_SOFT "soft" /
    Mapping is not default /
    +#define COLORD_RELATION_HARD "hard" /
    Explicitly mapped profile /
    +
    +#define COLORD_SPACE_RGB "rgb" /
    RGB colorspace /
    +#define COLORD_SPACE_CMYK "cmyk" /
    CMYK colorspace /
    +#define COLORD_SPACE_GRAY "gray" /
    Gray colorspace /
    +
    +#define COLORD_MODE_PHYSICAL "physical" /
    Actual device /
    +#define COLORD_MODE_VIRTUAL "virtual" /
    Virtual device with no hardware /
    +
    +#define COLORD_KIND_PRINTER "printer" /
    printing output device /
    +
    +/
    the timeout for connecting to colord /
    +#define COLORD_DBUS_TIMEOUT 5000 /
    ms /
    +
    +/
    This is static /
    +static DBusConnection *con = NULL;
    +
    +/
  • * 'colordStart()' - Get a connection to the system bus.
  • */
    +
    +void
    +colordStart(void)
    +{
  • if (con)
  • return;
  • con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
    +}

+/*

  • * 'colordStop()' - Release any connection to the system bus so that
  • * added profiles and devices are automatically removed.
  • */
    +
    +void
    +colordStop(void)
    +{
  • if (con == NULL)
  • return;
  • dbus_connection_unref(con);
  • con = NULL;
    +}

+/*

  • * 'message_dict_add_strings()' - add two strings to a dictionary.
  • */
    +
    +static void
    +message_dict_add_strings (DBusMessageIter *dict,
  •                      const char *key,
    
  •                      const char *value)
    
    +{
  •    DBusMessageIter entry;
    
  •    dbus_message_iter_open_container(dict,
    
  •                                     DBUS_TYPE_DICT_ENTRY,
    
  •                                     NULL,
    
  •                                     &entry);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
    
  •    dbus_message_iter_close_container(dict, &entry);
    
    +}
    +
    +/*
  • * 'colordCreateProfile()' - Create a color profile for a printer.
  • * Notes: When creating the device, we can create
  • /
    +
    +static void
    +colordCreateProfile (cups_array_t *profiles, /
    I - Profiles array */
  •                 const char _printer_name,  /_ I - Printer name */
    
  •                 const char _qualifier,     /_ I - Profile qualifier */
    
  •                 const char *_format,       /_ I - Profile qualifier format */
    
  •                 const char _iccfile,       /_ I - ICC filename */
    
  •                 const char _scope)         /_ I - The scope of the profile, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • char idstr; / Profile ID string */
  • size_t idstrlen; /* Profile ID allocated length */
  • const char profile_path; / Device object path */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the profile...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateProfile");
    
  • /* create a profile id */
  • idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1;
  • idstr = malloc (idstrlen);
  • if (!idstr)
  •  goto out;
    
  • snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile id of %s",
  •              idstr);
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                               DBUS_TYPE_ARRAY,
    
  •                               "{ss}",
    
  •                               &dict);
    
  • message_dict_add_strings(&dict, "Qualifier", qualifier);
  • message_dict_add_strings(&dict, "Format", format_str);
  • if (iccfile != NULL)
  • message_dict_add_strings(&dict, "Filename", iccfile);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)",
  •              idstr, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created profile %s",
    
  •              profile_path);
    
  • cupsArrayAdd(profiles, strdup(profile_path));

+out:

  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • free (idstr);
    +}

+/*

  • * 'colordDeviceAddProfile()' - Assign a profile to a device.
  • /
    +
    +static void
    +colordDeviceAddProfile (const char *device_path, /
    I - Device object path */
  •                    const char _profile_path,      /_ I - Profile object path */
    
  •                    const char _relation)          /_ I - Device relation, either 'soft' or 'hard' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     device_path,
    
  •                                     "org.freedesktop.ColorManager.Device",
    
  •                                     "AddProfile");
    
  • /* send profile path as the argument */
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "Calling %s:AddProfile(%s) [%s]",
    
  •              device_path, profile_path, relation);
    
  • /* send syncronous */
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to AddProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordCreateDevice()' - Create a device and register profiles.
  • /
    +
    +static void
    +colordCreateDevice (cupsd_printer_t *p, /
    I - Printer */
  •                ppd_file_t _ppd,            /_ I - PPD file */
    
  •                cups_array_t _profiles,     /_ I - Profiles array */
    
  •                const char _colorspace,     /_ I - Device colorspace, e.g. 'rgb' */
    
  •                const char _relation,       /_ I - Profile relation, either 'soft' or 'hard' */
    
  •                const char _scope)          /_ I - The scope of the device, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path; / Device object path */
  • const char profile_path; / Profile path */
  • char *default_profile_path = NULL;
  •                                            /\* Default profile path */
    
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Create the device...
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • device_path = device_id;
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                             DBUS_TYPE_ARRAY,
    
  •                             "{ss}",
    
  •                             &dict);
    
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • message_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
  • if (ppd->manufacturer != NULL)
  • message_dict_add_strings(&dict, "Vendor", ppd->manufacturer);
  • if (ppd->modelname != NULL)
  • message_dict_add_strings(&dict, "Model", ppd->modelname);
  • if (p->sanitized_device_uri != NULL)
  • message_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
  • message_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)",
  •              device_id, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created device %s",
    
  •              device_path);
    
  • /* add profiles */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path;
    
  •   profile_path = cupsArrayNext(profiles))
    
  • {
  • colordDeviceAddProfile (device_path, profile_path, relation);
  • }

+out:

  • free(default_profile_path);
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordDeleteDevice()' - Delete a device
  • /
    +
    +static void
    +colordDeleteDevice (const char *device_id) /
    I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • /*
  • * Create the device...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "DeleteDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    /\* this can happen normally on start-up */
    
  •    cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  •                    "failed to DeleteDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordGetQualifierFormat()' - Get the qualifier format.
  • * Notes: Returns a value of "ColorSpace.MediaType.Resolution" by default
  • /
    +
    +char *

    +colordGetQualifierFormat(ppd_file_t *ppd)
    +{
  • char *format; / Qualifier format tuple */
  • const char tmp; / Temporary string */
  • ppd_attr_t attr; / Profile attributes */
  • /* create 3-tuple */
  • format = calloc(3, sizeof(char*));
  • /* get 1st section */
  • tmp = "cupsICCQualifier1";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultColorSpace";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "DefaultColorModel";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[0] = strdup(tmp);
  • /* get 2st section */
  • tmp = "cupsICCQualifier2";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultMediaType";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[1] = strdup(tmp);
  • /* get 3st section */
  • tmp = "cupsICCQualifier3";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultResolution";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[2] = strdup(tmp);
  • return format;
    +}

+/*

  • * 'colordRegisterPrinter()' - Register profiles for a printer.
  • /
    +
    +void
    +colordRegisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char ppdfile[1024], /* PPD filename */
  •                    iccfile[1024];  /\* ICC filename */
    
  • ppd_file_t ppd; / PPD file */
  • cups_array_t profiles; / Profile paths array */
  • const char profile_key; / Profile keyword */
  • ppd_attr_t attr; / Profile attributes */
  • const char device_colorspace; / Device colorspace */
  • char *format; / Qualifier format tuple */
  • int i; /* Loop counter */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • /*
  • * Try opening the PPD file for this printer...
  • */
  • snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
  • if ((ppd = ppdOpenFile(ppdfile)) == NULL)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN,
  •                "cannot open %s",
    
  •                ppdfile);
    
  • return;
  • }
  • /*
  • * Find out the qualifier format
  • */
  • format = colordGetQualifierFormat(ppd);
  • /*
  • * See if we have any embedded profiles...
  • */
  • profiles = cupsArrayNew3 (NULL, NULL, NULL, 0, NULL,
  •                        (cups_afree_func_t) free);
    
  • profile_key = "cupsICCProfile";
  • attr = ppdFindAttr(ppd, profile_key, NULL);
  • for (; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
  • if (attr->spec[0] && attr->value && attr->value[0])
  • {
  •  if (attr->value[0] != '/')
    
  •    snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
    
  •             attr->value);
    
  •  else
    
  •    strlcpy(iccfile, attr->value, sizeof(iccfile));
    
  •  if (access(iccfile, 0))
    
  •  {
    
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "no access to %s",
    
  •                    iccfile);
    
  •    continue;
    
  •  }
    
  •  colordCreateProfile(profiles,
    
  •                      p->name,
    
  •                      attr->spec,
    
  •                      (const char **)format,
    
  •                      iccfile,
    
  •                      COLORD_SCOPE_TEMP);
    
  • }
  • /*
  • * Add the grayscale profile first. We always have a grayscale profile.
  • */
  • colordCreateProfile(profiles,
  •                  p->name,
    
  •                  "Gray..",
    
  •                  (const char **)format,
    
  •                  NULL,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Then add the RGB/CMYK/DeviceN color profile...
  • */
  • device_colorspace = "unknown";
  • switch (ppd->colorspace)
  • {
  • case PPD_CS_RGB :
  • case PPD_CS_CMY :
  •    device_colorspace = COLORD_SPACE_RGB;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "RGB..",
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_RGBK :
  • case PPD_CS_CMYK :
  •    device_colorspace = COLORD_SPACE_CMYK;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "CMYK..",
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_GRAY :
  •    device_colorspace = COLORD_SPACE_GRAY;
    
  •    break;
    
  • case PPD_CS_N :
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "DeviceN..",
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • }
  • /*
  • * Register the device with colord.
  • */
  • cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for "%s"",
  •              p->name);
    
  • colordCreateDevice (p,
  •                  ppd,
    
  •                  profiles,
    
  •                  device_colorspace,
    
  •                  COLORD_RELATION_SOFT,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Free any memory we used...
  • */
  • cupsArrayDelete(profiles);
  • for (i=0; i<3; i++)
  • free(format[i]);
  • free(format);
  • ppdClose(ppd);
    +}

+/*

  • * 'colordUnregisterPrinter()' - Unregister profiles for a printer.
  • /
    +
    +void
    +colordUnregisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • /*
  • * Just delete the device itself, and leave the profiles registered
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • colordDeleteDevice(device_id);
    +}

+#endif /* HAVE_DBUS /
+
+/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/colord.h b/scheduler/colord.h
    new file mode 100644
    index 0000000..262b695
    --- /dev/null
    +++ b/scheduler/colord.h
    @@ -0,0 +1,22 @@
    +/

  • * "$Id$"

  • * colord integration for the CUPS scheduler.

  • * Copyright 2011, Red Hat.

  • * These coded instructions, statements, and computer programs are the

  • * property of Apple Inc. and are protected by Federal copyright

  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"

  • * which should have been included with this file. If this file is

  • * file is missing or damaged, see the license at "http://www.cups.org/".

  • /
    +
    +void colordRegisterPrinter(cupsd_printer_t *p);
    +void colordUnregisterPrinter(cupsd_printer_t *p);
    +void colordStart(void);
    +void colordStop(void);
    +
    +/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/ipp.c b/scheduler/ipp.c
    index 289819f..409cba9 100644
    --- a/scheduler/ipp.c
    +++ b/scheduler/ipp.c
    @@ -2925,17 +2925,23 @@ add_printer(cupsd_client_t *con, /
    I - Client connection */

    cupsdSetPrinterReasons(printer, "none");

-#ifdef APPLE
/*
* (Re)register color profiles...
*/

 if (!RunUser)
 {
  •  cupsdCmsRegisterPrinter(printer);
    
    +#ifdef APPLE
  • /*
    
  •  \* FIXME: ideally the ColorSync stuff would be moved to colorsync.c
    
  •  \* and the colorsyncRegisterProfiles() would be called from
    
  •  \* cupsdCmsRegisterPrinter() in printers.c
    
  •  */
    
    apple_unregister_profiles(printer);
    apple_register_profiles(printer);
  • }
    #endif /* APPLE */
  • }
    }

/*
@@ -7008,11 +7014,17 @@ delete_printer(cupsd_client_t con, / I - Client connection */
snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
unlink(filename);

-#ifdef APPLE
/*

  • Unregister color profiles...
    */
  • cupsdCmsUnregisterPrinter(printer);
    +#ifdef APPLE
  • /*
  • * FIXME: ideally the ColorSync stuff would be moved to colorsync.c
  • * and the colorsyncUnregisterPrinter() would be called from
  • * cupsdCmsUnregisterPrinter() in printers.c
  • /
    apple_unregister_profiles(printer);
    #endif /
    APPLE */

diff --git a/scheduler/printers.c b/scheduler/printers.c
index d6ad2f3..fcdb035 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -77,6 +77,9 @@

include <sys/vfs.h>

#endif /* HAVE_SYS_VFS_H */

+#ifdef HAVE_DBUS
+# include "colord.h"
+#endif /* HAVE_DBUS */

/*

  • Local functions...
    @@ -708,6 +711,53 @@ cupsdDeleteAllPrinters(void)
    }
    }

+/*

  • * 'cupsdCmsRegisterPrinter()' - Registers a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsRegisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordRegisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsUnregisterPrinter()' - Unregisters a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsUnregisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordUnregisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStart()' - Starts the CMS
  • */
    +
    +void
    +cupsdCmsStart(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStart();
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStop()' - Stops the CMS
  • */
    +
    +void
    +cupsdCmsStop(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStop();
    +#endif /* defined(HAVE_DBUS) */
    +}

/*

  • 'cupsdDeletePrinter()' - Delete a printer from the system.
    @@ -748,6 +798,12 @@ cupsdDeletePrinter(
    "Job stopped.");

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • If this printer is the next for browsing, point to the next one...
      */

@@ -1411,6 +1467,12 @@ cupsdRenamePrinter(
}

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • Rename the printer...
      */

@@ -2647,6 +2709,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t p)/ I - Printer to setup /
#endif /
__sgi */

/*

  • * Re-register profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • cupsdCmsRegisterPrinter(p);
  • /*
    • Let the browse protocols reflect the change
      */

diff --git a/scheduler/printers.h b/scheduler/printers.h
index 1751578..3820428 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -170,6 +170,10 @@ extern const char _cupsdValidateDest(const char *uri,
cups_ptype_t *dtype,
cupsd_printer_t *_printer);
extern void cupsdWritePrintcap(void);
+extern void cupsdCmsRegisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsUnregisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsStart(void);
+extern void cupsdCmsStop(void);

/*

1.7.5.1

Collaborator

michaelrsweet commented May 23, 2012

"0001-Add-colord-support-to-CUPS-which-allows-Linux-printe_v4.patch":

From 294f3d07c957734a32a4679def6a9590a691ee71 Mon Sep 17 00:00:00 2001
From: Richard Hughes richard@hughsie.com
Date: Tue, 1 Mar 2011 16:05:48 +0000
Subject: [PATCH] Add colord support to CUPS which allows Linux printers to be
color managed

This functionality is possible because of lots of help from Tim Waugh -- thanks!

scheduler/Makefile | 1 +
scheduler/colord.c | 692 ++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/colord.h | 22 ++
scheduler/ipp.c | 18 +-
scheduler/printers.c | 69 +++++
scheduler/printers.h | 4 +
6 files changed, 803 insertions(+), 3 deletions(-)
create mode 100644 scheduler/colord.c
create mode 100644 scheduler/colord.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 3c7da8e..b9c47d3 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -27,6 +27,7 @@ CUPSDOBJS =
file.o
main.o
ipp.o \

  •   colord.o \
    listen.o \
    job.o \
    log.o \
    
    diff --git a/scheduler/colord.c b/scheduler/colord.c
    new file mode 100644
    index 0000000..45ce431
    --- /dev/null
    +++ b/scheduler/colord.c
    @@ -0,0 +1,692 @@
    +/*
  • * "$Id$"
  • * colord integration for the CUPS scheduler.
  • * Copyright 2011, Red Hat.
  • * These coded instructions, statements, and computer programs are the
  • * property of Apple Inc. and are protected by Federal copyright
  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"
  • * which should have been included with this file. If this file is
  • * file is missing or damaged, see the license at "http://www.cups.org/".
  • * Contents:
  • * colordRegisterPrinter() - Register profiles for a printer.
  • * colordUnregisterPrinter() - Unregister profiles for a printer.
  • * colordStart() - Get a connection to the system bus.
  • * colordStop() - Release any connection to the system bus
  • * so that added profiles and devices are
  • * automatically removed.
  • /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#ifdef HAVE_DBUS
    +
    +#include <dbus/dbus.h>
    +#include <cups/ppd-private.h>
    +
    +/
  • * Defines used by colord. See the reference docs for further details:
  • * http://colord.hughsie.com/api/ref-dbus.html
  • /
    +#define COLORD_SCOPE_NORMAL "normal" /
    System scope /
    +#define COLORD_SCOPE_TEMP "temp" /
    Process scope /
    +#define COLORD_SCOPE_DISK "disk" /
    Lives forever, as stored in DB /
    +
    +#define COLORD_RELATION_SOFT "soft" /
    Mapping is not default /
    +#define COLORD_RELATION_HARD "hard" /
    Explicitly mapped profile /
    +
    +#define COLORD_SPACE_RGB "rgb" /
    RGB colorspace /
    +#define COLORD_SPACE_CMYK "cmyk" /
    CMYK colorspace /
    +#define COLORD_SPACE_GRAY "gray" /
    Gray colorspace /
    +#define COLORD_SPACE_UNKNOWN "unknown" /
    Unknown colorspace /
    +
    +#define COLORD_MODE_PHYSICAL "physical" /
    Actual device /
    +#define COLORD_MODE_VIRTUAL "virtual" /
    Virtual device with no hardware /
    +
    +#define COLORD_KIND_PRINTER "printer" /
    printing output device /
    +
    +/
    the timeout for connecting to colord /
    +#define COLORD_DBUS_TIMEOUT 5000 /
    ms /
    +
    +/
    This is static /
    +static DBusConnection *con = NULL;
    +
    +/
  • * 'colordStart()' - Get a connection to the system bus.
  • */
    +
    +void
    +colordStart(void)
    +{
  • if (con)
  • return;
  • con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
    +}

+/*

  • * 'colordStop()' - Release any connection to the system bus so that
  • * added profiles and devices are automatically removed.
  • */
    +
    +void
    +colordStop(void)
    +{
  • if (con == NULL)
  • return;
  • dbus_connection_unref(con);
  • con = NULL;
    +}

+/*

  • * 'message_dict_add_strings()' - add two strings to a dictionary.
  • */
    +
    +static void
    +message_dict_add_strings (DBusMessageIter *dict,
  •                      const char *key,
    
  •                      const char *value)
    
    +{
  •    DBusMessageIter entry;
    
  •    dbus_message_iter_open_container(dict,
    
  •                                     DBUS_TYPE_DICT_ENTRY,
    
  •                                     NULL,
    
  •                                     &entry);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
    
  •    dbus_message_iter_close_container(dict, &entry);
    
    +}
    +
    +/*
  • * 'colordCreateProfile()' - Create a color profile for a printer.
  • * Notes: When creating the device, we can create
  • /
    +
    +static void
    +colordCreateProfile (cups_array_t *profiles, /
    I - Profiles array */
  •                 const char _printer_name,  /_ I - Printer name */
    
  •                 const char _qualifier,     /_ I - Profile qualifier */
    
  •                 const char _colorspace,    /_ I - Profile colorspace */
    
  •                 const char *_format,       /_ I - Profile qualifier format */
    
  •                 const char _iccfile,       /_ I - ICC filename */
    
  •                 const char _scope)         /_ I - The scope of the profile, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • char idstr; / Profile ID string */
  • size_t idstrlen; /* Profile ID allocated length */
  • const char profile_path; / Device object path */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the profile...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateProfile");
    
  • /* create a profile id */
  • idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1;
  • idstr = malloc (idstrlen);
  • if (!idstr)
  •  goto out;
    
  • snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile id of %s",
  •              idstr);
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                               DBUS_TYPE_ARRAY,
    
  •                               "{ss}",
    
  •                               &dict);
    
  • message_dict_add_strings(&dict, "Qualifier", qualifier);
  • message_dict_add_strings(&dict, "Format", format_str);
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • if (iccfile != NULL)
  • message_dict_add_strings(&dict, "Filename", iccfile);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)",
  •              idstr, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created profile %s",
    
  •              profile_path);
    
  • cupsArrayAdd(profiles, strdup(profile_path));

+out:

  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • free (idstr);
    +}

+/*

  • * 'colordDeviceAddProfile()' - Assign a profile to a device.
  • /
    +
    +static void
    +colordDeviceAddProfile (const char *device_path, /
    I - Device object path */
  •                    const char _profile_path,      /_ I - Profile object path */
    
  •                    const char _relation)          /_ I - Device relation, either 'soft' or 'hard' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     device_path,
    
  •                                     "org.freedesktop.ColorManager.Device",
    
  •                                     "AddProfile");
    
  • /* send profile path as the argument */
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "Calling %s:AddProfile(%s) [%s]",
    
  •              device_path, profile_path, relation);
    
  • /* send syncronous */
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to AddProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordCreateDevice()' - Create a device and register profiles.
  • /
    +
    +static void
    +colordCreateDevice (cupsd_printer_t *p, /
    I - Printer */
  •                ppd_file_t _ppd,            /_ I - PPD file */
    
  •                cups_array_t _profiles,     /_ I - Profiles array */
    
  •                const char _colorspace,     /_ I - Device colorspace, e.g. 'rgb' */
    
  •                char *_format,              /_ I - Device qualifier format */
    
  •                const char _relation,       /_ I - Profile relation, either 'soft' or 'hard' */
    
  •                const char _scope)          /_ I - The scope of the device, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path; / Device object path */
  • const char profile_path; / Profile path */
  • char *default_profile_path = NULL;
  •                                            /\* Default profile path */
    
  • char device_id[1024]; /* Device ID as understood by colord */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the device...
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • device_path = device_id;
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                             DBUS_TYPE_ARRAY,
    
  •                             "{ss}",
    
  •                             &dict);
    
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • message_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
  • if (ppd->manufacturer != NULL)
  • message_dict_add_strings(&dict, "Vendor", ppd->manufacturer);
  • if (ppd->modelname != NULL)
  • message_dict_add_strings(&dict, "Model", ppd->modelname);
  • if (p->sanitized_device_uri != NULL)
  • message_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
  • message_dict_add_strings(&dict, "Format", format_str);
  • message_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)",
  •              device_id, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created device %s",
    
  •              device_path);
    
  • /* add profiles */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path;
    
  •   profile_path = cupsArrayNext(profiles))
    
  • {
  • colordDeviceAddProfile (device_path, profile_path, relation);
  • }

+out:

  • free(default_profile_path);
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordDeleteDevice()' - Delete a device
  • /
    +
    +static void
    +colordDeleteDevice (const char *device_id) /
    I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • /*
  • * Create the device...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "DeleteDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    /\* this can happen normally on start-up */
    
  •    cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  •                    "failed to DeleteDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordGetQualifierFormat()' - Get the qualifier format.
  • * Notes: Returns a value of "ColorSpace.MediaType.Resolution" by default
  • /
    +
    +char *

    +colordGetQualifierFormat(ppd_file_t *ppd)
    +{
  • char *format; / Qualifier format tuple */
  • const char tmp; / Temporary string */
  • ppd_attr_t attr; / Profile attributes */
  • /* create 3-tuple */
  • format = calloc(3, sizeof(char*));
  • /* get 1st section */
  • tmp = "cupsICCQualifier1";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultColorSpace";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "DefaultColorModel";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[0] = strdup(tmp);
  • /* get 2nd section */
  • tmp = "cupsICCQualifier2";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultMediaType";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[1] = strdup(tmp);
  • /* get 3rd section */
  • tmp = "cupsICCQualifier3";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultResolution";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[2] = strdup(tmp);
  • return format;
    +}

+/*

  • * 'colordRegisterPrinter()' - Register profiles for a printer.
  • /
    +
    +void
    +colordRegisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char ppdfile[1024], /* PPD filename */
  •                    iccfile[1024];  /\* ICC filename */
    
  • ppd_file_t ppd; / PPD file */
  • cups_array_t profiles; / Profile paths array */
  • const char profile_key; / Profile keyword */
  • ppd_attr_t attr; / Profile attributes */
  • const char device_colorspace; / Device colorspace */
  • char *format; / Qualifier format tuple */
  • int i; /* Loop counter */
  • /*
  • * Do nothing for discovered printers as they will have local color
  • * correction
  • */
  • if (p->type & CUPS_PRINTER_DISCOVERED)
  • return;
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • if (con == NULL)
  • return;
  • /*
  • * Try opening the PPD file for this printer...
  • */
  • snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
  • if ((ppd = ppdOpenFile(ppdfile)) == NULL)
  • {
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •                "cannot open %s",
    
  •                ppdfile);
    
  • return;
  • }
  • /*
  • * Find out the qualifier format
  • */
  • format = colordGetQualifierFormat(ppd);
  • /*
  • * See if we have any embedded profiles...
  • */
  • profiles = cupsArrayNew3 (NULL, NULL, NULL, 0, NULL,
  •                        (cups_afree_func_t) free);
    
  • profile_key = "cupsICCProfile";
  • attr = ppdFindAttr(ppd, profile_key, NULL);
  • for (; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
  • if (attr->spec[0] && attr->value && attr->value[0])
  • {
  •  if (attr->value[0] != '/')
    
  •    snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
    
  •             attr->value);
    
  •  else
    
  •    strlcpy(iccfile, attr->value, sizeof(iccfile));
    
  •  if (access(iccfile, 0))
    
  •  {
    
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "no access to %s",
    
  •                    iccfile);
    
  •    continue;
    
  •  }
    
  •  colordCreateProfile(profiles,
    
  •                      p->name,
    
  •                      attr->spec,
    
  •                      COLORD_SPACE_UNKNOWN,
    
  •                      (const char **)format,
    
  •                      iccfile,
    
  •                      COLORD_SCOPE_TEMP);
    
  • }
  • /*
  • * Add the grayscale profile first. We always have a grayscale profile.
  • */
  • colordCreateProfile(profiles,
  •                  p->name,
    
  •                  "Gray..",
    
  •                  COLORD_SPACE_GRAY,
    
  •                  (const char **)format,
    
  •                  NULL,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Then add the RGB/CMYK/DeviceN color profile...
  • */
  • device_colorspace = "unknown";
  • switch (ppd->colorspace)
  • {
  • case PPD_CS_RGB :
  • case PPD_CS_CMY :
  •    device_colorspace = COLORD_SPACE_RGB;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "RGB..",
    
  •                        COLORD_SPACE_RGB,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_RGBK :
  • case PPD_CS_CMYK :
  •    device_colorspace = COLORD_SPACE_CMYK;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "CMYK..",
    
  •                        COLORD_SPACE_CMYK,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_GRAY :
  •    device_colorspace = COLORD_SPACE_GRAY;
    
  •    break;
    
  • case PPD_CS_N :
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "DeviceN..",
    
  •                        COLORD_SPACE_UNKNOWN,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • }
  • /*
  • * Register the device with colord.
  • */
  • cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for "%s"",
  •              p->name);
    
  • colordCreateDevice (p,
  •                  ppd,
    
  •                  profiles,
    
  •                  device_colorspace,
    
  •                  format,
    
  •                  COLORD_RELATION_SOFT,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Free any memory we used...
  • */
  • cupsArrayDelete(profiles);
  • for (i=0; i<3; i++)
  • free(format[i]);
  • free(format);
  • ppdClose(ppd);
    +}

+/*

  • * 'colordUnregisterPrinter()' - Unregister profiles for a printer.
  • /
    +
    +void
    +colordUnregisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • if (con == NULL)
  • return;
  • /*
  • * Just delete the device itself, and leave the profiles registered
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • colordDeleteDevice(device_id);
    +}

+#endif /* HAVE_DBUS /
+
+/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/colord.h b/scheduler/colord.h
    new file mode 100644
    index 0000000..262b695
    --- /dev/null
    +++ b/scheduler/colord.h
    @@ -0,0 +1,22 @@
    +/

  • * "$Id$"

  • * colord integration for the CUPS scheduler.

  • * Copyright 2011, Red Hat.

  • * These coded instructions, statements, and computer programs are the

  • * property of Apple Inc. and are protected by Federal copyright

  • * law. Distribution and use rights are outlined in the file "LICENSE.txt"

  • * which should have been included with this file. If this file is

  • * file is missing or damaged, see the license at "http://www.cups.org/".

  • /
    +
    +void colordRegisterPrinter(cupsd_printer_t *p);
    +void colordUnregisterPrinter(cupsd_printer_t *p);
    +void colordStart(void);
    +void colordStop(void);
    +
    +/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/ipp.c b/scheduler/ipp.c
    index a048baa..0066d72 100644
    --- a/scheduler/ipp.c
    +++ b/scheduler/ipp.c
    @@ -2925,17 +2925,23 @@ add_printer(cupsd_client_t *con, /
    I - Client connection */

    cupsdSetPrinterReasons(printer, "none");

-#ifdef APPLE
/*
* (Re)register color profiles...
*/

 if (!RunUser)
 {
  •  cupsdCmsRegisterPrinter(printer);
    
    +#ifdef APPLE
  • /*
    
  •  \* FIXME: ideally the ColorSync stuff would be moved to colorsync.c
    
  •  \* and the colorsyncRegisterProfiles() would be called from
    
  •  \* cupsdCmsRegisterPrinter() in printers.c
    
  •  */
    
    apple_unregister_profiles(printer);
    apple_register_profiles(printer);
  • }
    #endif /* APPLE */
  • }
    }

/*
@@ -7032,11 +7038,17 @@ delete_printer(cupsd_client_t con, / I - Client connection */
snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
unlink(filename);

-#ifdef APPLE
/*

  • Unregister color profiles...
    */
  • cupsdCmsUnregisterPrinter(printer);
    +#ifdef APPLE
  • /*
  • * FIXME: ideally the ColorSync stuff would be moved to colorsync.c
  • * and the colorsyncUnregisterPrinter() would be called from
  • * cupsdCmsUnregisterPrinter() in printers.c
  • /
    apple_unregister_profiles(printer);
    #endif /
    APPLE */

diff --git a/scheduler/printers.c b/scheduler/printers.c
index 4686c4c..8e49e6a 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -80,6 +80,9 @@

include <asl.h>

#endif /* APPLE */

+#ifdef HAVE_DBUS
+# include "colord.h"
+#endif /* HAVE_DBUS */

/*

  • Local functions...
    @@ -712,6 +715,53 @@ cupsdDeleteAllPrinters(void)
    }
    }

+/*

  • * 'cupsdCmsRegisterPrinter()' - Registers a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsRegisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordRegisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsUnregisterPrinter()' - Unregisters a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsUnregisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordUnregisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStart()' - Starts the CMS
  • */
    +
    +void
    +cupsdCmsStart(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStart();
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStop()' - Stops the CMS
  • */
    +
    +void
    +cupsdCmsStop(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStop();
    +#endif /* defined(HAVE_DBUS) */
    +}

/*

  • 'cupsdDeletePrinter()' - Delete a printer from the system.
    @@ -752,6 +802,12 @@ cupsdDeletePrinter(
    "Job stopped.");

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • If this printer is the next for browsing, point to the next one...
      */

@@ -1418,6 +1474,12 @@ cupsdRenamePrinter(
}

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • Rename the printer...
      */

@@ -2644,6 +2706,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t p)/ I - Printer to setup /
#endif /
__sgi */

/*

  • * Re-register profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • cupsdCmsRegisterPrinter(p);
  • /*
    • Let the browse protocols reflect the change
      */

diff --git a/scheduler/printers.h b/scheduler/printers.h
index 1751578..3820428 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -170,6 +170,10 @@ extern const char _cupsdValidateDest(const char *uri,
cups_ptype_t *dtype,
cupsd_printer_t *_printer);
extern void cupsdWritePrintcap(void);
+extern void cupsdCmsRegisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsUnregisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsStart(void);
+extern void cupsdCmsStop(void);

/*

1.7.6

Collaborator

michaelrsweet commented May 23, 2012

"0001-Add-colord-support-to-CUPS-which-allows-Linux-printe_v5.patch":

From 28b511590cc841feb301ad781f99687580cee475 Mon Sep 17 00:00:00 2001
From: Richard Hughes richard@hughsie.com
Date: Tue, 1 Mar 2011 16:05:48 +0000
Subject: [PATCH] Add colord support to CUPS which allows Linux printers to be
color managed

This functionality is possible because of lots of help from Tim Waugh -- thanks!

scheduler/Makefile | 1 +
scheduler/colord.c | 710 ++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/colord.h | 41 +++
scheduler/ipp.c | 18 +-
scheduler/printers.c | 69 +++++
scheduler/printers.h | 4 +
6 files changed, 840 insertions(+), 3 deletions(-)
create mode 100644 scheduler/colord.c
create mode 100644 scheduler/colord.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 3c7da8e..b9c47d3 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -27,6 +27,7 @@ CUPSDOBJS =
file.o
main.o
ipp.o \

  •   colord.o \
    listen.o \
    job.o \
    log.o \
    
    diff --git a/scheduler/colord.c b/scheduler/colord.c
    new file mode 100644
    index 0000000..2cbc705
    --- /dev/null
    +++ b/scheduler/colord.c
    @@ -0,0 +1,710 @@
    +/*
  • * "$Id$"
  • * colord integration for the CUPS scheduler.
  • * Copyright 2011 Red Hat, Inc.
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • * Contents:
  • * colordRegisterPrinter() - Register profiles for a printer.
  • * colordUnregisterPrinter() - Unregister profiles for a printer.
  • * colordStart() - Get a connection to the system bus.
  • * colordStop() - Release any connection to the system bus
  • * so that added profiles and devices are
  • * automatically removed.
  • /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#ifdef HAVE_DBUS
    +
    +#include <dbus/dbus.h>
    +#include <cups/ppd-private.h>
    +
    +/
  • * Defines used by colord. See the reference docs for further details:
  • * http://colord.hughsie.com/api/ref-dbus.html
  • /
    +#define COLORD_SCOPE_NORMAL "normal" /
    System scope /
    +#define COLORD_SCOPE_TEMP "temp" /
    Process scope /
    +#define COLORD_SCOPE_DISK "disk" /
    Lives forever, as stored in DB /
    +
    +#define COLORD_RELATION_SOFT "soft" /
    Mapping is not default /
    +#define COLORD_RELATION_HARD "hard" /
    Explicitly mapped profile /
    +
    +#define COLORD_SPACE_RGB "rgb" /
    RGB colorspace /
    +#define COLORD_SPACE_CMYK "cmyk" /
    CMYK colorspace /
    +#define COLORD_SPACE_GRAY "gray" /
    Gray colorspace /
    +#define COLORD_SPACE_UNKNOWN "unknown" /
    Unknown colorspace /
    +
    +#define COLORD_MODE_PHYSICAL "physical" /
    Actual device /
    +#define COLORD_MODE_VIRTUAL "virtual" /
    Virtual device with no hardware /
    +
    +#define COLORD_KIND_PRINTER "printer" /
    printing output device /
    +
    +/
    the timeout for connecting to colord /
    +#define COLORD_DBUS_TIMEOUT 5000 /
    ms /
    +
    +/
    This is static /
    +static DBusConnection *con = NULL;
    +
    +/
  • * 'colordStart()' - Get a connection to the system bus.
  • */
    +
    +void
    +colordStart(void)
    +{
  • if (con)
  • return;
  • con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
    +}

+/*

  • * 'colordStop()' - Release any connection to the system bus so that
  • * added profiles and devices are automatically removed.
  • */
    +
    +void
    +colordStop(void)
    +{
  • if (con == NULL)
  • return;
  • dbus_connection_unref(con);
  • con = NULL;
    +}

+/*

  • * 'message_dict_add_strings()' - add two strings to a dictionary.
  • */
    +
    +static void
    +message_dict_add_strings (DBusMessageIter *dict,
  •                      const char *key,
    
  •                      const char *value)
    
    +{
  •    DBusMessageIter entry;
    
  •    dbus_message_iter_open_container(dict,
    
  •                                     DBUS_TYPE_DICT_ENTRY,
    
  •                                     NULL,
    
  •                                     &entry);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
    
  •    dbus_message_iter_close_container(dict, &entry);
    
    +}
    +
    +/*
  • * 'colordCreateProfile()' - Create a color profile for a printer.
  • * Notes: When creating the device, we can create
  • /
    +
    +static void
    +colordCreateProfile (cups_array_t *profiles, /
    I - Profiles array */
  •                 const char _printer_name,  /_ I - Printer name */
    
  •                 const char _qualifier,     /_ I - Profile qualifier */
    
  •                 const char _colorspace,    /_ I - Profile colorspace */
    
  •                 const char *_format,       /_ I - Profile qualifier format */
    
  •                 const char _iccfile,       /_ I - ICC filename */
    
  •                 const char _scope)         /_ I - The scope of the profile, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • char idstr; / Profile ID string */
  • size_t idstrlen; /* Profile ID allocated length */
  • const char profile_path; / Device object path */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the profile...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateProfile");
    
  • /* create a profile id */
  • idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1;
  • idstr = malloc (idstrlen);
  • if (!idstr)
  •  goto out;
    
  • snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile id of %s",
  •              idstr);
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                               DBUS_TYPE_ARRAY,
    
  •                               "{ss}",
    
  •                               &dict);
    
  • message_dict_add_strings(&dict, "Qualifier", qualifier);
  • message_dict_add_strings(&dict, "Format", format_str);
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • if (iccfile != NULL)
  • message_dict_add_strings(&dict, "Filename", iccfile);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)",
  •              idstr, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created profile %s",
    
  •              profile_path);
    
  • cupsArrayAdd(profiles, strdup(profile_path));

+out:

  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • free (idstr);
    +}

+/*

  • * 'colordDeviceAddProfile()' - Assign a profile to a device.
  • /
    +
    +static void
    +colordDeviceAddProfile (const char *device_path, /
    I - Device object path */
  •                    const char _profile_path,      /_ I - Profile object path */
    
  •                    const char _relation)          /_ I - Device relation, either 'soft' or 'hard' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     device_path,
    
  •                                     "org.freedesktop.ColorManager.Device",
    
  •                                     "AddProfile");
    
  • /* send profile path as the argument */
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "Calling %s:AddProfile(%s) [%s]",
    
  •              device_path, profile_path, relation);
    
  • /* send syncronous */
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to AddProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordCreateDevice()' - Create a device and register profiles.
  • /
    +
    +static void
    +colordCreateDevice (cupsd_printer_t *p, /
    I - Printer */
  •                ppd_file_t _ppd,            /_ I - PPD file */
    
  •                cups_array_t _profiles,     /_ I - Profiles array */
    
  •                const char _colorspace,     /_ I - Device colorspace, e.g. 'rgb' */
    
  •                char *_format,              /_ I - Device qualifier format */
    
  •                const char _relation,       /_ I - Profile relation, either 'soft' or 'hard' */
    
  •                const char _scope)          /_ I - The scope of the device, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path; / Device object path */
  • const char profile_path; / Profile path */
  • char *default_profile_path = NULL;
  •                                            /\* Default profile path */
    
  • char device_id[1024]; /* Device ID as understood by colord */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the device...
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • device_path = device_id;
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                             DBUS_TYPE_ARRAY,
    
  •                             "{ss}",
    
  •                             &dict);
    
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • message_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
  • if (ppd->manufacturer != NULL)
  • message_dict_add_strings(&dict, "Vendor", ppd->manufacturer);
  • if (ppd->modelname != NULL)
  • message_dict_add_strings(&dict, "Model", ppd->modelname);
  • if (p->sanitized_device_uri != NULL)
  • message_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
  • message_dict_add_strings(&dict, "Format", format_str);
  • message_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)",
  •              device_id, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created device %s",
    
  •              device_path);
    
  • /* add profiles */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path;
    
  •   profile_path = cupsArrayNext(profiles))
    
  • {
  • colordDeviceAddProfile (device_path, profile_path, relation);
  • }

+out:

  • free(default_profile_path);
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordDeleteDevice()' - Delete a device
  • /
    +
    +static void
    +colordDeleteDevice (const char *device_id) /
    I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • /*
  • * Create the device...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "DeleteDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    /\* this can happen normally on start-up */
    
  •    cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  •                    "failed to DeleteDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordGetQualifierFormat()' - Get the qualifier format.
  • * Notes: Returns a value of "ColorSpace.MediaType.Resolution" by default
  • /
    +
    +char *

    +colordGetQualifierFormat(ppd_file_t *ppd)
    +{
  • char *format; / Qualifier format tuple */
  • const char tmp; / Temporary string */
  • ppd_attr_t attr; / Profile attributes */
  • /* create 3-tuple */
  • format = calloc(3, sizeof(char*));
  • /* get 1st section */
  • tmp = "cupsICCQualifier1";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultColorSpace";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "DefaultColorModel";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[0] = strdup(tmp);
  • /* get 2nd section */
  • tmp = "cupsICCQualifier2";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultMediaType";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[1] = strdup(tmp);
  • /* get 3rd section */
  • tmp = "cupsICCQualifier3";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultResolution";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[2] = strdup(tmp);
  • return format;
    +}

+/*

  • * 'colordRegisterPrinter()' - Register profiles for a printer.
  • /
    +
    +void
    +colordRegisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char ppdfile[1024], /* PPD filename */
  •                    iccfile[1024];  /\* ICC filename */
    
  • ppd_file_t ppd; / PPD file */
  • cups_array_t profiles; / Profile paths array */
  • const char profile_key; / Profile keyword */
  • ppd_attr_t attr; / Profile attributes */
  • const char device_colorspace; / Device colorspace */
  • char *format; / Qualifier format tuple */
  • int i; /* Loop counter */
  • /*
  • * Do nothing for discovered printers as they will have local color
  • * correction
  • */
  • if (p->type & CUPS_PRINTER_DISCOVERED)
  • return;
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • if (con == NULL)
  • return;
  • /*
  • * Try opening the PPD file for this printer...
  • */
  • snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
  • if ((ppd = ppdOpenFile(ppdfile)) == NULL)
  • {
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •                "cannot open %s",
    
  •                ppdfile);
    
  • return;
  • }
  • /*
  • * Find out the qualifier format
  • */
  • format = colordGetQualifierFormat(ppd);
  • /*
  • * See if we have any embedded profiles...
  • */
  • profiles = cupsArrayNew3 (NULL, NULL, NULL, 0, NULL,
  •                        (cups_afree_func_t) free);
    
  • profile_key = "cupsICCProfile";
  • attr = ppdFindAttr(ppd, profile_key, NULL);
  • for (; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
  • if (attr->spec[0] && attr->value && attr->value[0])
  • {
  •  if (attr->value[0] != '/')
    
  •    snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
    
  •             attr->value);
    
  •  else
    
  •    strlcpy(iccfile, attr->value, sizeof(iccfile));
    
  •  if (access(iccfile, 0))
    
  •  {
    
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "no access to %s",
    
  •                    iccfile);
    
  •    continue;
    
  •  }
    
  •  colordCreateProfile(profiles,
    
  •                      p->name,
    
  •                      attr->spec,
    
  •                      COLORD_SPACE_UNKNOWN,
    
  •                      (const char **)format,
    
  •                      iccfile,
    
  •                      COLORD_SCOPE_TEMP);
    
  • }
  • /*
  • * Add the grayscale profile first. We always have a grayscale profile.
  • */
  • colordCreateProfile(profiles,
  •                  p->name,
    
  •                  "Gray..",
    
  •                  COLORD_SPACE_GRAY,
    
  •                  (const char **)format,
    
  •                  NULL,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Then add the RGB/CMYK/DeviceN color profile...
  • */
  • device_colorspace = "unknown";
  • switch (ppd->colorspace)
  • {
  • case PPD_CS_RGB :
  • case PPD_CS_CMY :
  •    device_colorspace = COLORD_SPACE_RGB;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "RGB..",
    
  •                        COLORD_SPACE_RGB,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_RGBK :
  • case PPD_CS_CMYK :
  •    device_colorspace = COLORD_SPACE_CMYK;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "CMYK..",
    
  •                        COLORD_SPACE_CMYK,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_GRAY :
  •    device_colorspace = COLORD_SPACE_GRAY;
    
  •    break;
    
  • case PPD_CS_N :
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "DeviceN..",
    
  •                        COLORD_SPACE_UNKNOWN,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • }
  • /*
  • * Register the device with colord.
  • */
  • cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for "%s"",
  •              p->name);
    
  • colordCreateDevice (p,
  •                  ppd,
    
  •                  profiles,
    
  •                  device_colorspace,
    
  •                  format,
    
  •                  COLORD_RELATION_SOFT,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Free any memory we used...
  • */
  • cupsArrayDelete(profiles);
  • for (i=0; i<3; i++)
  • free(format[i]);
  • free(format);
  • ppdClose(ppd);
    +}

+/*

  • * 'colordUnregisterPrinter()' - Unregister profiles for a printer.
  • /
    +
    +void
    +colordUnregisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • if (con == NULL)
  • return;
  • /*
  • * Just delete the device itself, and leave the profiles registered
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • colordDeleteDevice(device_id);
    +}

+#endif /* HAVE_DBUS /
+
+/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/colord.h b/scheduler/colord.h
    new file mode 100644
    index 0000000..75bdd3b
    --- /dev/null
    +++ b/scheduler/colord.h
    @@ -0,0 +1,41 @@
    +/

  • * "$Id$"

  • * colord integration for the CUPS scheduler.

  • * Copyright 2011 Red Hat, Inc.

  • * Redistribution and use in source and binary forms, with or without

  • * modification, are permitted provided that the following conditions

  • * are met:

  • * Redistributions of source code must retain the above copyright

  • * notice, this list of conditions and the following disclaimer.

  • * Redistributions in binary form must reproduce the above copyright

  • * notice, this list of conditions and the following disclaimer in the

  • * documentation and/or other materials provided with the distribution.

  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,

  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,

  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED

  • * OF THE POSSIBILITY OF SUCH DAMAGE.

  • /
    +
    +void colordRegisterPrinter(cupsd_printer_t *p);
    +void colordUnregisterPrinter(cupsd_printer_t *p);
    +void colordStart(void);
    +void colordStop(void);
    +
    +/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/ipp.c b/scheduler/ipp.c
    index a048baa..0066d72 100644
    --- a/scheduler/ipp.c
    +++ b/scheduler/ipp.c
    @@ -2925,17 +2925,23 @@ add_printer(cupsd_client_t *con, /
    I - Client connection */

    cupsdSetPrinterReasons(printer, "none");

-#ifdef APPLE
/*
* (Re)register color profiles...
*/

 if (!RunUser)
 {
  •  cupsdCmsRegisterPrinter(printer);
    
    +#ifdef APPLE
  • /*
    
  •  \* FIXME: ideally the ColorSync stuff would be moved to colorsync.c
    
  •  \* and the colorsyncRegisterProfiles() would be called from
    
  •  \* cupsdCmsRegisterPrinter() in printers.c
    
  •  */
    
    apple_unregister_profiles(printer);
    apple_register_profiles(printer);
  • }
    #endif /* APPLE */
  • }
    }

/*
@@ -7032,11 +7038,17 @@ delete_printer(cupsd_client_t con, / I - Client connection */
snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
unlink(filename);

-#ifdef APPLE
/*

  • Unregister color profiles...
    */
  • cupsdCmsUnregisterPrinter(printer);
    +#ifdef APPLE
  • /*
  • * FIXME: ideally the ColorSync stuff would be moved to colorsync.c
  • * and the colorsyncUnregisterPrinter() would be called from
  • * cupsdCmsUnregisterPrinter() in printers.c
  • /
    apple_unregister_profiles(printer);
    #endif /
    APPLE */

diff --git a/scheduler/printers.c b/scheduler/printers.c
index 4686c4c..8e49e6a 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -80,6 +80,9 @@

include <asl.h>

#endif /* APPLE */

+#ifdef HAVE_DBUS
+# include "colord.h"
+#endif /* HAVE_DBUS */

/*

  • Local functions...
    @@ -712,6 +715,53 @@ cupsdDeleteAllPrinters(void)
    }
    }

+/*

  • * 'cupsdCmsRegisterPrinter()' - Registers a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsRegisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordRegisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsUnregisterPrinter()' - Unregisters a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsUnregisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordUnregisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStart()' - Starts the CMS
  • */
    +
    +void
    +cupsdCmsStart(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStart();
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStop()' - Stops the CMS
  • */
    +
    +void
    +cupsdCmsStop(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStop();
    +#endif /* defined(HAVE_DBUS) */
    +}

/*

  • 'cupsdDeletePrinter()' - Delete a printer from the system.
    @@ -752,6 +802,12 @@ cupsdDeletePrinter(
    "Job stopped.");

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • If this printer is the next for browsing, point to the next one...
      */

@@ -1418,6 +1474,12 @@ cupsdRenamePrinter(
}

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • Rename the printer...
      */

@@ -2644,6 +2706,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t p)/ I - Printer to setup /
#endif /
__sgi */

/*

  • * Re-register profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • cupsdCmsRegisterPrinter(p);
  • /*
    • Let the browse protocols reflect the change
      */

diff --git a/scheduler/printers.h b/scheduler/printers.h
index 1751578..3820428 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -170,6 +170,10 @@ extern const char _cupsdValidateDest(const char *uri,
cups_ptype_t *dtype,
cupsd_printer_t *_printer);
extern void cupsdWritePrintcap(void);
+extern void cupsdCmsRegisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsUnregisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsStart(void);
+extern void cupsdCmsStop(void);

/*

1.7.6

Collaborator

michaelrsweet commented May 23, 2012

"0001-Add-colord-support-to-CUPS-which-allows-Linux-printe_v6.patch":

From db29c24e3ff75938775aa1f4072e346aeb7f6a9c Mon Sep 17 00:00:00 2001
From: Richard Hughes richard@hughsie.com
Date: Tue, 1 Mar 2011 16:05:48 +0000
Subject: [PATCH] Add colord support to CUPS which allows Linux printers to be
color managed

This functionality is possible because of lots of help from Tim Waugh -- thanks!

scheduler/Makefile | 1 +
scheduler/colord.c | 784 ++++++++++++++++++++++++++++++++++++++++++++++++++
scheduler/colord.h | 41 +++
scheduler/ipp.c | 18 +-
scheduler/printers.c | 69 +++++
scheduler/printers.h | 4 +
6 files changed, 914 insertions(+), 3 deletions(-)
create mode 100644 scheduler/colord.c
create mode 100644 scheduler/colord.h

diff --git a/scheduler/Makefile b/scheduler/Makefile
index 3c7da8e..b9c47d3 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -27,6 +27,7 @@ CUPSDOBJS =
file.o
main.o
ipp.o \

  •   colord.o \
    listen.o \
    job.o \
    log.o \
    
    diff --git a/scheduler/colord.c b/scheduler/colord.c
    new file mode 100644
    index 0000000..bd06e1c
    --- /dev/null
    +++ b/scheduler/colord.c
    @@ -0,0 +1,784 @@
    +/*
  • * "$Id$"
  • * colord integration for the CUPS scheduler.
  • * Copyright 2011 Red Hat, Inc.
  • * Redistribution and use in source and binary forms, with or without
  • * modification, are permitted provided that the following conditions
  • * are met:
  • * Redistributions of source code must retain the above copyright
  • * notice, this list of conditions and the following disclaimer.
  • * Redistributions in binary form must reproduce the above copyright
  • * notice, this list of conditions and the following disclaimer in the
  • * documentation and/or other materials provided with the distribution.
  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  • * OF THE POSSIBILITY OF SUCH DAMAGE.
  • * Contents:
  • * colordRegisterPrinter() - Register profiles for a printer.
  • * colordUnregisterPrinter() - Unregister profiles for a printer.
  • * colordStart() - Get a connection to the system bus.
  • * colordStop() - Release any connection to the system bus
  • * so that added profiles and devices are
  • * automatically removed.
  • /
    +
    +/
  • * Include necessary headers...
  • /
    +
    +#include "cupsd.h"
    +
    +#ifdef HAVE_DBUS
    +
    +#include <dbus/dbus.h>
    +#include <cups/ppd-private.h>
    +
    +/
  • * Defines used by colord. See the reference docs for further details:
  • * http://colord.hughsie.com/api/ref-dbus.html
  • /
    +#define COLORD_SCOPE_NORMAL "normal" /
    System scope /
    +#define COLORD_SCOPE_TEMP "temp" /
    Process scope /
    +#define COLORD_SCOPE_DISK "disk" /
    Lives forever, as stored in DB /
    +
    +#define COLORD_RELATION_SOFT "soft" /
    Mapping is not default /
    +#define COLORD_RELATION_HARD "hard" /
    Explicitly mapped profile /
    +
    +#define COLORD_SPACE_RGB "rgb" /
    RGB colorspace /
    +#define COLORD_SPACE_CMYK "cmyk" /
    CMYK colorspace /
    +#define COLORD_SPACE_GRAY "gray" /
    Gray colorspace /
    +#define COLORD_SPACE_UNKNOWN "unknown" /
    Unknown colorspace /
    +
    +#define COLORD_MODE_PHYSICAL "physical" /
    Actual device /
    +#define COLORD_MODE_VIRTUAL "virtual" /
    Virtual device with no hardware /
    +
    +#define COLORD_KIND_PRINTER "printer" /
    printing output device /
    +
    +/
    the timeout for connecting to colord /
    +#define COLORD_DBUS_TIMEOUT 5000 /
    ms /
    +
    +/
    This is static /
    +static DBusConnection *con = NULL;
    +
    +/
  • * 'colordStart()' - Get a connection to the system bus.
  • */
    +
    +void
    +colordStart(void)
    +{
  • if (con)
  • return;
  • con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL);
    +}

+/*

  • * 'colordStop()' - Release any connection to the system bus so that
  • * added profiles and devices are automatically removed.
  • */
    +
    +void
    +colordStop(void)
    +{
  • if (con == NULL)
  • return;
  • dbus_connection_unref(con);
  • con = NULL;
    +}

+/*

  • * 'message_dict_add_strings()' - add two strings to a dictionary.
  • */
    +
    +static void
    +message_dict_add_strings (DBusMessageIter *dict,
  •                      const char *key,
    
  •                      const char *value)
    
    +{
  •    DBusMessageIter entry;
    
  •    dbus_message_iter_open_container(dict,
    
  •                                     DBUS_TYPE_DICT_ENTRY,
    
  •                                     NULL,
    
  •                                     &entry);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
    
  •    dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
    
  •    dbus_message_iter_close_container(dict, &entry);
    
    +}
    +
    +/*
  • * 'colordCreateProfile()' - Create a color profile for a printer.
  • * Notes: When creating the device, we can create
  • /
    +
    +static void
    +colordCreateProfile (cups_array_t *profiles, /
    I - Profiles array */
  •                 const char _printer_name,  /_ I - Printer name */
    
  •                 const char _qualifier,     /_ I - Profile qualifier */
    
  •                 const char _colorspace,    /_ I - Profile colorspace */
    
  •                 const char *_format,       /_ I - Profile qualifier format */
    
  •                 const char _iccfile,       /_ I - ICC filename */
    
  •                 const char _scope)         /_ I - The scope of the profile, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • char idstr; / Profile ID string */
  • size_t idstrlen; /* Profile ID allocated length */
  • const char profile_path; / Device object path */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the profile...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateProfile");
    
  • /* create a profile id */
  • idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1;
  • idstr = malloc (idstrlen);
  • if (!idstr)
  •  goto out;
    
  • snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile id of %s",
  •              idstr);
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                               DBUS_TYPE_ARRAY,
    
  •                               "{ss}",
    
  •                               &dict);
    
  • message_dict_add_strings(&dict, "Qualifier", qualifier);
  • message_dict_add_strings(&dict, "Format", format_str);
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • if (iccfile != NULL)
  • message_dict_add_strings(&dict, "Filename", iccfile);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)",
  •              idstr, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created profile %s",
    
  •              profile_path);
    
  • cupsArrayAdd(profiles, strdup(profile_path));

+out:

  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • free (idstr);
    +}

+/*

  • * 'colordDeviceAddProfile()' - Assign a profile to a device.
  • /
    +
    +static void
    +colordDeviceAddProfile (const char *device_path, /
    I - Device object path */
  •                    const char _profile_path,      /_ I - Profile object path */
    
  •                    const char _relation)          /_ I - Device relation, either 'soft' or 'hard' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     device_path,
    
  •                                     "org.freedesktop.ColorManager.Device",
    
  •                                     "AddProfile");
    
  • /* send profile path as the argument */
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "Calling %s:AddProfile(%s) [%s]",
    
  •              device_path, profile_path, relation);
    
  • /* send syncronous */
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to AddProfile: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordCreateDevice()' - Create a device and register profiles.
  • /
    +
    +static void
    +colordCreateDevice (cupsd_printer_t *p, /
    I - Printer */
  •                ppd_file_t _ppd,            /_ I - PPD file */
    
  •                cups_array_t _profiles,     /_ I - Profiles array */
    
  •                const char _colorspace,     /_ I - Device colorspace, e.g. 'rgb' */
    
  •                char *_format,              /_ I - Device qualifier format */
    
  •                const char _relation,       /_ I - Profile relation, either 'soft' or 'hard' */
    
  •                const char _scope)          /_ I - The scope of the device, e.g.
    
  •                                                   'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path; / Device object path */
  • const char profile_path; / Profile path */
  • char *default_profile_path = NULL;
  •                                            /\* Default profile path */
    
  • char device_id[1024]; /* Device ID as understood by colord */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the device...
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • device_path = device_id;
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "CreateDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • /* mush the qualifier format into a simple string */
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s",
  •       format[0],
    
  •       format[1],
    
  •       format[2]);
    
  • /* set initial properties */
  • dbus_message_iter_open_container(&args,
  •                             DBUS_TYPE_ARRAY,
    
  •                             "{ss}",
    
  •                             &dict);
    
  • message_dict_add_strings(&dict, "Colorspace", colorspace);
  • message_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
  • if (ppd->manufacturer != NULL)
  • message_dict_add_strings(&dict, "Vendor", ppd->manufacturer);
  • if (ppd->modelname != NULL)
  • message_dict_add_strings(&dict, "Model", ppd->modelname);
  • if (p->sanitized_device_uri != NULL)
  • message_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
  • message_dict_add_strings(&dict, "Format", format_str);
  • message_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
  • dbus_message_iter_close_container(&args, &dict);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)",
  •              device_id, scope);
    
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to CreateDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •              "created device %s",
    
  •              device_path);
    
  • /* add profiles */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path;
    
  •   profile_path = cupsArrayNext(profiles))
    
  • {
  • colordDeviceAddProfile (device_path, profile_path, relation);
  • }

+out:

  • free(default_profile_path);
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordFindDeviceById()' - Finds a device
  • /
    +
    +static char *
    +colordFindDeviceById (const char *device_id) /
    I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path_tmp; / Device object path */
  • char device_path = NULL; / Device object path */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "FindDeviceById");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    /\* this can happen normally on start-up */
    
  •    cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  •                    "failed to DeleteDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
  • /* get reply data */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "incorrect reply type");
    
  •    goto out;
    
  • }
  • dbus_message_iter_get_basic(&args, &device_path_tmp);
  • if (device_path_tmp != NULL)
  • device_path = strdup (device_path_tmp);
    +out:
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
  • return device_path;
    +}

+/*

  • * 'colordDeleteDevice()' - Delete a device
  • /
    +
    +static void
    +colordDeleteDevice (const char *device_id) /
    I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • char device_path; / Device object path */
  • /*
  • * Find the device...
  • */
  • device_path = colordFindDeviceById (device_id);
  • if (device_path == NULL)
  • {
  •    /\* this can happen normally on start-up */
    
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "failed to find device: %s",
    
  •                    device_id);
    
  •    goto out;
    
  • }
  • /*
  • * Delete the device...
  • */
  • message = dbus_message_new_method_call("org.freedesktop.ColorManager",
  •                                     "/org/freedesktop/ColorManager",
    
  •                                     "org.freedesktop.ColorManager",
    
  •                                     "DeleteDevice");
    
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /* send syncronous */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(con,
  •                                                message,
    
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (reply == NULL)
  • {
  •    /\* this can happen normally on start-up */
    
  •    cupsdLogMessage(CUPSD_LOG_DEBUG,
    
  •                    "failed to DeleteDevice: %s:%s",
    
  •                    error.name, error.message);
    
  •    dbus_error_free(&error);
    
  •    goto out;
    
  • }
    +out:
  • free (device_path);
  • if (message != NULL)
  • dbus_message_unref(message);
  • if (reply != NULL)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colordGetQualifierFormat()' - Get the qualifier format.
  • * Notes: Returns a value of "ColorSpace.MediaType.Resolution" by default
  • /
    +
    +char *

    +colordGetQualifierFormat(ppd_file_t *ppd)
    +{
  • char *format; / Qualifier format tuple */
  • const char tmp; / Temporary string */
  • ppd_attr_t attr; / Profile attributes */
  • /* create 3-tuple */
  • format = calloc(3, sizeof(char*));
  • /* get 1st section */
  • tmp = "cupsICCQualifier1";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultColorSpace";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "DefaultColorModel";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[0] = strdup(tmp);
  • /* get 2nd section */
  • tmp = "cupsICCQualifier2";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultMediaType";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[1] = strdup(tmp);
  • /* get 3rd section */
  • tmp = "cupsICCQualifier3";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • if (attr != NULL)
  • tmp = attr->value;
  • else
  • {
  • tmp = "DefaultResolution";
  • attr = ppdFindAttr(ppd, tmp, NULL);
  • }
  • if (attr == NULL)
  • {
  • tmp = "";
  • }
  • if (strncmp(tmp, "Default", 7) == 0)
  • tmp += 7;
  • format[2] = strdup(tmp);
  • return format;
    +}

+/*

  • * 'colordRegisterPrinter()' - Register profiles for a printer.
  • /
    +
    +void
    +colordRegisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char ppdfile[1024], /* PPD filename */
  •                    iccfile[1024];  /\* ICC filename */
    
  • ppd_file_t ppd; / PPD file */
  • cups_array_t profiles; / Profile paths array */
  • const char profile_key; / Profile keyword */
  • ppd_attr_t attr; / Profile attributes */
  • const char device_colorspace; / Device colorspace */
  • char *format; / Qualifier format tuple */
  • int i; /* Loop counter */
  • /*
  • * Do nothing for discovered printers as they will have local color
  • * correction
  • */
  • if (p->type & CUPS_PRINTER_DISCOVERED)
  • return;
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • if (con == NULL)
  • return;
  • /*
  • * Try opening the PPD file for this printer...
  • */
  • snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
  • if ((ppd = ppdOpenFile(ppdfile)) == NULL)
  • {
  • cupsdLogMessage(CUPSD_LOG_DEBUG,
  •                "cannot open %s",
    
  •                ppdfile);
    
  • return;
  • }
  • /*
  • * Find out the qualifier format
  • */
  • format = colordGetQualifierFormat(ppd);
  • /*
  • * See if we have any embedded profiles...
  • */
  • profiles = cupsArrayNew3 (NULL, NULL, NULL, 0, NULL,
  •                        (cups_afree_func_t) free);
    
  • profile_key = "cupsICCProfile";
  • attr = ppdFindAttr(ppd, profile_key, NULL);
  • for (; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
  • if (attr->spec[0] && attr->value && attr->value[0])
  • {
  •  if (attr->value[0] != '/')
    
  •    snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
    
  •             attr->value);
    
  •  else
    
  •    strlcpy(iccfile, attr->value, sizeof(iccfile));
    
  •  if (access(iccfile, 0))
    
  •  {
    
  •    cupsdLogMessage(CUPSD_LOG_WARN,
    
  •                    "no access to %s",
    
  •                    iccfile);
    
  •    continue;
    
  •  }
    
  •  colordCreateProfile(profiles,
    
  •                      p->name,
    
  •                      attr->spec,
    
  •                      COLORD_SPACE_UNKNOWN,
    
  •                      (const char **)format,
    
  •                      iccfile,
    
  •                      COLORD_SCOPE_TEMP);
    
  • }
  • /*
  • * Add the grayscale profile first. We always have a grayscale profile.
  • */
  • colordCreateProfile(profiles,
  •                  p->name,
    
  •                  "Gray..",
    
  •                  COLORD_SPACE_GRAY,
    
  •                  (const char **)format,
    
  •                  NULL,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Then add the RGB/CMYK/DeviceN color profile...
  • */
  • device_colorspace = "unknown";
  • switch (ppd->colorspace)
  • {
  • case PPD_CS_RGB :
  • case PPD_CS_CMY :
  •    device_colorspace = COLORD_SPACE_RGB;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "RGB..",
    
  •                        COLORD_SPACE_RGB,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_RGBK :
  • case PPD_CS_CMYK :
  •    device_colorspace = COLORD_SPACE_CMYK;
    
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "CMYK..",
    
  •                        COLORD_SPACE_CMYK,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_GRAY :
  •    device_colorspace = COLORD_SPACE_GRAY;
    
  •    break;
    
  • case PPD_CS_N :
  •    colordCreateProfile(profiles,
    
  •                        p->name,
    
  •                        "DeviceN..",
    
  •                        COLORD_SPACE_UNKNOWN,
    
  •                        (const char **)format,
    
  •                        NULL,
    
  •                        COLORD_SCOPE_TEMP);
    
  •    break;
    
  • }
  • /*
  • * Register the device with colord.
  • */
  • cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for "%s"",
  •              p->name);
    
  • colordCreateDevice (p,
  •                  ppd,
    
  •                  profiles,
    
  •                  device_colorspace,
    
  •                  format,
    
  •                  COLORD_RELATION_SOFT,
    
  •                  COLORD_SCOPE_TEMP);
    
  • /*
  • * Free any memory we used...
  • */
  • cupsArrayDelete(profiles);
  • for (i=0; i<3; i++)
  • free(format[i]);
  • free(format);
  • ppdClose(ppd);
    +}

+/*

  • * 'colordUnregisterPrinter()' - Unregister profiles for a printer.
  • /
    +
    +void
    +colordUnregisterPrinter(cupsd_printer_t *p) /
    I - printer */
    +{
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Ensure we have a DBus connection
  • */
  • colordStart();
  • if (con == NULL)
  • return;
  • /*
  • * Just delete the device itself, and leave the profiles registered
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • colordDeleteDevice(device_id);
    +}

+#endif /* HAVE_DBUS /
+
+/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/colord.h b/scheduler/colord.h
    new file mode 100644
    index 0000000..75bdd3b
    --- /dev/null
    +++ b/scheduler/colord.h
    @@ -0,0 +1,41 @@
    +/

  • * "$Id$"

  • * colord integration for the CUPS scheduler.

  • * Copyright 2011 Red Hat, Inc.

  • * Redistribution and use in source and binary forms, with or without

  • * modification, are permitted provided that the following conditions

  • * are met:

  • * Redistributions of source code must retain the above copyright

  • * notice, this list of conditions and the following disclaimer.

  • * Redistributions in binary form must reproduce the above copyright

  • * notice, this list of conditions and the following disclaimer in the

  • * documentation and/or other materials provided with the distribution.

  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,

  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,

  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED

  • * OF THE POSSIBILITY OF SUCH DAMAGE.

  • /
    +
    +void colordRegisterPrinter(cupsd_printer_t *p);
    +void colordUnregisterPrinter(cupsd_printer_t *p);
    +void colordStart(void);
    +void colordStop(void);
    +
    +/

  • * End of "$Id$".

  • /
    diff --git a/scheduler/ipp.c b/scheduler/ipp.c
    index b9903d1..b5af36f 100644
    --- a/scheduler/ipp.c
    +++ b/scheduler/ipp.c
    @@ -2921,17 +2921,23 @@ add_printer(cupsd_client_t *con, /
    I - Client connection */

    cupsdSetPrinterReasons(printer, "none");

-#ifdef APPLE
/*
* (Re)register color profiles...
*/

 if (!RunUser)
 {
  •  cupsdCmsRegisterPrinter(printer);
    
    +#ifdef APPLE
  • /*
    
  •  \* FIXME: ideally the ColorSync stuff would be moved to colorsync.c
    
  •  \* and the colorsyncRegisterProfiles() would be called from
    
  •  \* cupsdCmsRegisterPrinter() in printers.c
    
  •  */
    
    apple_unregister_profiles(printer);
    apple_register_profiles(printer);
  • }
    #endif /* APPLE */
  • }
    }

/*
@@ -7028,11 +7034,17 @@ delete_printer(cupsd_client_t con, / I - Client connection */
snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
unlink(filename);

-#ifdef APPLE
/*

  • Unregister color profiles...
    */
  • cupsdCmsUnregisterPrinter(printer);
    +#ifdef APPLE
  • /*
  • * FIXME: ideally the ColorSync stuff would be moved to colorsync.c
  • * and the colorsyncUnregisterPrinter() would be called from
  • * cupsdCmsUnregisterPrinter() in printers.c
  • /
    apple_unregister_profiles(printer);
    #endif /
    APPLE */

diff --git a/scheduler/printers.c b/scheduler/printers.c
index 6920801..e830499 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -80,6 +80,9 @@

include <asl.h>

#endif /* APPLE */

+#ifdef HAVE_DBUS
+# include "colord.h"
+#endif /* HAVE_DBUS */

/*

  • Local functions...
    @@ -712,6 +715,53 @@ cupsdDeleteAllPrinters(void)
    }
    }

+/*

  • * 'cupsdCmsRegisterPrinter()' - Registers a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsRegisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordRegisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsUnregisterPrinter()' - Unregisters a printer and profiles with the CMS
  • */
    +
    +void
    +cupsdCmsUnregisterPrinter(cupsd_printer_t *p)
    +{
    +#if defined(HAVE_DBUS)
  • colordUnregisterPrinter(p);
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStart()' - Starts the CMS
  • */
    +
    +void
    +cupsdCmsStart(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStart();
    +#endif /* defined(HAVE_DBUS) _/
    +}

+/_

  • * 'cupsdCmsStop()' - Stops the CMS
  • */
    +
    +void
    +cupsdCmsStop(void)
    +{
    +#if defined(HAVE_DBUS)
  • colordStop();
    +#endif /* defined(HAVE_DBUS) */
    +}

/*

  • 'cupsdDeletePrinter()' - Delete a printer from the system.
    @@ -752,6 +802,12 @@ cupsdDeletePrinter(
    "Job stopped.");

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • If this printer is the next for browsing, point to the next one...
      */

@@ -1418,6 +1474,12 @@ cupsdRenamePrinter(
}

/*

  • * Unregister profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • /*
    • Rename the printer...
      */

@@ -2644,6 +2706,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t p)/ I - Printer to setup /
#endif /
__sgi */

/*

  • * Re-register profiles...
  • */
  • cupsdCmsUnregisterPrinter(p);
  • cupsdCmsRegisterPrinter(p);
  • /*
    • Let the browse protocols reflect the change
      */

diff --git a/scheduler/printers.h b/scheduler/printers.h
index 1751578..3820428 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -170,6 +170,10 @@ extern const char _cupsdValidateDest(const char *uri,
cups_ptype_t *dtype,
cupsd_printer_t *_printer);
extern void cupsdWritePrintcap(void);
+extern void cupsdCmsRegisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsUnregisterPrinter(cupsd_printer_t *p);
+extern void cupsdCmsStart(void);
+extern void cupsdCmsStop(void);

/*

1.7.6.2

Collaborator

michaelrsweet commented May 23, 2012

"str3808.patch":

Index: scheduler/colorman.c

--- scheduler/colorman.c (revision 10490)
+++ scheduler/colorman.c (working copy)
@@ -12,6 +12,32 @@

  • which should have been included with this file. If this file is
  • file is missing or damaged, see the license at "http://www.cups.org/".
  • * Original DBUS/colord code is Copyright 2011 Red Hat, Inc.

  • * Redistribution and use in source and binary forms, with or without

  • * modification, are permitted provided that the following conditions

  • * are met:

  • * Redistributions of source code must retain the above copyright

  • * notice, this list of conditions and the following disclaimer.

  • * Redistributions in binary form must reproduce the above copyright

  • * notice, this list of conditions and the following disclaimer in the

  • * documentation and/or other materials provided with the distribution.

  • * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

  • * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

  • * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS

  • * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE

  • * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,

  • * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

  • * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

  • * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

  • * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,

  • * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

  • * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED

  • * OF THE POSSIBILITY OF SUCH DAMAGE.

  • Contents:
    *
    */
    @@ -27,10 +53,58 @@

    include <ApplicationServices/ApplicationServices.h>

    extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id);

    include <CoreFoundation/CoreFoundation.h>

    +#elif defined(HAVE_DBUS)
    +# include <dbus/dbus.h>
    +
    +/*

    • * Defines used by colord. See the reference docs for further details:
    • * http://colord.hughsie.com/api/ref-dbus.html
    • */
      +
      +# define COLORD_SCOPE_NORMAL "normal"
    •               /\* System scope _/
      
      +# define COLORD_SCOPE_TEMP "temp" /_ Process scope /
      +# define COLORD_SCOPE_DISK "disk" /
      Lives forever, as stored in DB /
      +
      +# define COLORD_RELATION_SOFT "soft" /
      Mapping is not default /
      +# define COLORD_RELATION_HARD "hard" /
      Explicitly mapped profile /
      +
      +# define COLORD_SPACE_RGB "rgb" /
      RGB colorspace /
      +# define COLORD_SPACE_CMYK "cmyk" /
      CMYK colorspace /
      +# define COLORD_SPACE_GRAY "gray" /
      Gray colorspace */
      +# define COLORD_SPACE_UNKNOWN "unknown"
    •               /\* Unknown colorspace */
      
      +# define COLORD_MODE_PHYSICAL "physical"
    •               /\* Actual device */
      
      +# define COLORD_MODE_VIRTUAL "virtual"
    •               /\* Virtual device with no hardware */
      
      +# define COLORD_KIND_PRINTER "printer"
    •               /\* printing output device */
      
      +# define COLORD_DBUS_MSG(p,m) dbus_message_new_method_call(\
    •               "org.freedesktop.ColorManager", (p),\
      
    •                                    "org.freedesktop.ColorManager", (m))
      
    •                                    /\* Macro to make new colord messages */
      
      +# define COLORD_DBUS_PATH "/org/freedesktop/ColorManager"
    •               /\* Path for color management system _/
      
      +# define COLORD_DBUS_TIMEOUT 5000 /_ Timeout for connecting to colord in ms /
      #endif /
      APPLE */

    /*

    • * Local globals...
    • */
      +
      +#if !defined(APPLE) && defined(HAVE_DBUS)
      +static DBusConnection *colord_con = NULL;
    •               /\* DBUS connection for colord _/
      
      +#endif /_ !APPLE && HAVE_DBUS /
      +
      +
      +/
  • Local functions...
    */

@@ -41,6 +115,28 @@
const char *text, const char *iccfile);
static void apple_register_profiles(cupsd_printer_t *p);
static void apple_unregister_profiles(cupsd_printer_t *p);
+
+#elif defined(HAVE_DBUS)
+static void colord_create_device(cupsd_printer_t *p, ppd_file_t *ppd,

  •                cups_array_t *profiles,
    
  •                const char _colorspace, char *_format,
    
  •                const char *relation, const char *scope);
    
    +static void colord_create_profile(cups_array_t *profiles,
  •                 const char *printer_name,
    
  •                 const char *qualifier,
    
  •                 const char *colorspace,
    
  •                 char **format, const char *iccfile,
    
  •                 const char *scope);
    
    +static void colord_delete_device(const char *device_id);
    +static void colord_device_add_profile(const char *device_path,
  •                 const char *profile_path,
    
  •                 const char *relation);
    
    +static void colord_dict_add_strings(DBusMessageIter *dict,
  •               const char _key, const char *value);
    
    +static char *colord_find_device(const char *device_id);
    +static void colord_get_qualifier_format(ppd_file_t *ppd, char *format[3]);
    +static void colord_register_printer(cupsd_printer_t *p);
    +static void colord_unregister_printer(cupsd_printer_t *p);
    #endif /_ APPLE */

@@ -56,7 +152,8 @@
apple_register_profiles(p);

#elif defined(HAVE_DBUS)

  • /* colord stuff goes here */
  • colord_unregister_printer(p);
  • colord_register_printer(p);
    #endif /* APPLE */
    }

@@ -69,7 +166,7 @@
cupsdStartColor(void)
{
#if !defined(APPLE) && defined(HAVE_DBUS)

  • /* colord stuff goes here */
  • colord_con = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
    #endif /* !APPLE && HAVE_DBUS */
    }

@@ -82,7 +179,8 @@
cupsdStopColor(void)
{
#if !defined(APPLE) && defined(HAVE_DBUS)

  • /* colord stuff goes here */
  • dbus_connection_unref(colord_con);
  • colord_con = NULL;
    #endif /* !APPLE && HAVE_DBUS */
    }

@@ -98,7 +196,7 @@
apple_unregister_profiles(p);

#elif defined(HAVE_DBUS)

  • /* colord stuff goes here */
  • colord_unregister_printer(p);
    #endif /* APPLE */
    }

@@ -239,7 +337,6 @@
const char q1_choice, / ColorModel (or other) choice /
*q2_choice, /
MediaType (or other) choice /
*q3_choice; /
Resolution (or other) choice */

  • const char profile_key; / Profile keyword /
    ppd_option_t *cm_option; /
    Color model option /
    ppd_choice_t *cm_choice; /
    Color model choice /
    int num_profiles; /
    Number of profiles */
    @@ -275,15 +372,9 @@
  • See if we have any profiles...
    */
  • if ((attr = ppdFindAttr(ppd, "APTiogaProfile", NULL)) != NULL)
  • profile_key = "APTiogaProfile";
  • else
  • {
  • attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
  • profile_key = "cupsICCProfile";

- }

  • for (num_profiles = 0; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))

  • for (num_profiles = 0, attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);

  •   attr;
    
  •   attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
    

    if (attr->spec[0] && attr->value && attr->value[0])
    {
    if (attr->value[0] != '/')
    @@ -325,77 +416,61 @@

    if (num_profiles > 0)
    {

  • if (profile_key[0] == 'A')

  • /*

  • * For CUPS PPDs, figure out the default profile selector values...

  • */

  • if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL &&
  • attr->value && attr->value[0])
    {
  • /*
    
  •  \* For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile
    
  •  \* attribute...
    
  •  */
    
  •  snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
    
  •  q1_attr = ppdFindAttr(ppd, q_keyword, NULL);
    
  • }
  • else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL)
  •  q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
    
  •  if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL &&
    
  • attr->value)
    
  •    default_profile_id = atoi(attr->value);
    
  • if (q1_attr && q1_attr->value && q1_attr->value[0])
  •  q1_choice = q1_attr->value;
    
  • else
  •  q1_choice = "";
    
  •  q1_choice = q2_choice = q3_choice = NULL;
    
  • if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
  • attr->value && attr->value[0])
  • {
  •  snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
    
  •  q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
    
    }
    else
  • {
  • /*
    
  •  \* For CUPS PPDs, figure out the default profile selector values...
    
  •  */
    
  •  q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
    
  •  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL &&
    
  • attr->value && attr->value[0])
    
  •  {
    
  • snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
  • q1_attr = ppdFindAttr(ppd, q_keyword, NULL);
  •  }
    
  •  else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL)
    
  • q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
  • if (q2_attr && q2_attr->value && q2_attr->value[0])
  •  q2_choice = q2_attr->value;
    
  • else
  •  q2_choice = NULL;
    
  •  if (q1_attr && q1_attr->value && q1_attr->value[0])
    
  • q1_choice = q1_attr->value;
  •  else
    
  • q1_choice = "";
  • if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
  • attr->value && attr->value[0])
  • {
  •  snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
    
  •  q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
    
  • }
  • else
  •  q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
    
  •  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
    
  • attr->value && attr->value[0])
    
  •  {
    
  • snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
  • q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
  •  }
    
  •  else
    
  • q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
  • if (q3_attr && q3_attr->value && q3_attr->value[0])
  •  q3_choice = q3_attr->value;
    
  • else
  •  q3_choice = NULL;
    
  •  if (q2_attr && q2_attr->value && q2_attr->value[0])
    
  • q2_choice = q2_attr->value;
  •  else
    

- q2_choice = NULL;

  •  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
    
  • attr->value && attr->value[0])
    
  •  {
    
  • snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
  • q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
  •  }
    
  •  else
    

- q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);

  •  if (q3_attr && q3_attr->value && q3_attr->value[0])
    
  • q3_choice = q3_attr->value;
  •  else
    
  • q3_choice = NULL;

- }

/*
 * Loop through the profiles listed in the PPD...
 */

 languages = _ppdGetLanguages(ppd);
  • for (attr = ppdFindAttr(ppd, profile_key, NULL);
  • for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
    attr;
  • attr = ppdFindNextAttr(ppd, profile_key, NULL))
  • attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
    if (attr->spec[0] && attr->value && attr->value[0])
    {
    /*
    @@ -412,22 +487,17 @@
    cupsdLogFCMessage, p))
    continue;
  •    if (profile_key[0] == 'c')
    
  • {
  • cupsArraySave(ppd->sorted_attrs);
    
  • cupsArraySave(ppd->sorted_attrs);
  • if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID",
    
  •                   attr->spec)) != NULL &&
    
  •     profileid_attr->value && isdigit(profileid_attr->value[0] & 255))
    
  •   profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10);
    
  • else
    

- profile_id = _ppdHashName(attr->spec);

  • cupsArrayRestore(ppd->sorted_attrs);
    
  •    }
    
  • if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID",
  •                 attr->spec)) != NULL &&
    
  •   profileid_attr->value && isdigit(profileid_attr->value[0] & 255))
    
  • profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10);
    
    else
  • profile_id = atoi(attr->spec);
    
  • profile_id = _ppdHashName(attr->spec);
    
  • cupsArrayRestore(ppd->sorted_attrs);

profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
@@ -789,12 +859,6 @@

if (ColorSyncUnregisterDevice != NULL)
{

  • /*
  • * Because we may have registered the printer profiles using a prior device
  • * ID-based UUID, remove both the old style UUID and current UUID for the
  • * printer.

- */

 CFUUIDRef deviceUUID;      /* Device UUID */

 deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name));

@@ -805,10 +869,626 @@
}
}
}
+
+
#elif defined(HAVE_DBUS)
+/*

  • * 'colord_create_device()' - Create a device and register profiles.
  • */

+static void
+colord_create_device(

  • cupsd_printer_t p, / I - Printer */
  • ppd_file_t ppd, / I - PPD file */
  • cups_array_t profiles, / I - Profiles array */
  • const char colorspace, / I - Device colorspace, e.g. 'rgb' */
  • char *format, / I - Device qualifier format */
  • const char relation, / I - Profile relation, either 'soft'
  •                      or 'hard' */
    
  • const char scope) / I - The scope of the device, e.g.
  •                      'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path; / Device object path */
  • const char profile_path; / Profile path */
  • char *default_profile_path = NULL;
  •               /\* Default profile path */
    
  • char device_id[1024]; /* Device ID as understood by colord */
  • char format_str[1024]; /* Qualifier format as a string */

-/* colord stuff goes here */
+

  • /*
  • * Create the device...
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • device_path = device_id;
  • message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "CreateDevice");
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1],
  •       format[2]);
    
  • dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict);
  • colord_dict_add_strings(&dict, "Colorspace", colorspace);
  • colord_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
  • if (ppd->manufacturer)
  • colord_dict_add_strings(&dict, "Vendor", ppd->manufacturer);
  • if (ppd->modelname)
  • colord_dict_add_strings(&dict, "Model", ppd->modelname);
  • if (p->sanitized_device_uri)
  • colord_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
  • colord_dict_add_strings(&dict, "Format", format_str);
  • colord_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
  • dbus_message_iter_close_container(&args, &dict);
  • /*
  • * Send the CreateDevice request synchronously...
  • */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)", device_id,
  •              scope);
    
  • reply = dbus_connection_send_with_reply_and_block(colord_con, message,
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (!reply)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN, "CreateDevice failed: %s:%s", error.name,
  •                error.message);
    
  • dbus_error_free(&error);
  • goto out;
  • }
  • /*
  • * Get reply data...
  • */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN,
  •                "CreateDevice failed: Incorrect reply type.");
    
  • goto out;
  • }
  • dbus_message_iter_get_basic(&args, &device_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Created device "%s".", device_path);
  • /*
  • * Add profiles...
  • */
  • for (profile_path = cupsArrayFirst(profiles);
  •   profile_path;
    
  •   profile_path = cupsArrayNext(profiles))
    
  • {
  • colord_device_add_profile(device_path, profile_path, relation);
  • }

+out:
+

  • if (default_profile_path)
  • free(default_profile_path);
  • if (message)
  • dbus_message_unref(message);
  • if (reply)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colord_create_profile()' - Create a color profile for a printer.
  • */
    +
    +static void
    +colord_create_profile(
  • cups_array_t profiles, / I - Profiles array */
  • const char printer_name, / I - Printer name */
  • const char qualifier, / I - Profile qualifier */
  • const char colorspace, / I - Profile colorspace */
  • char *format, / I - Profile qualifier format */
  • const char iccfile, / I - ICC filename */
  • const char scope) / I - The scope of the profile, e.g.
  •                          'normal', 'temp' or 'disk' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusMessageIter dict; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • char idstr; / Profile ID string */
  • size_t idstrlen; /* Profile ID allocated length */
  • const char profile_path; / Device object path */
  • char format_str[1024]; /* Qualifier format as a string */
  • /*
  • * Create the profile...
  • */
  • message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "CreateProfile");
  • idstrlen = strlen(printer_name) + 1 + strlen(qualifier) + 1;
  • if ((idstr = malloc(idstrlen)) == NULL)
  • goto out;
  • snprintf(idstr, idstrlen, "%s-%s", printer_name, qualifier);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile ID "%s".", idstr);
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
  • snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1],
  •       format[2]);
    
  • dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict);
  • colord_dict_add_strings(&dict, "Qualifier", qualifier);
  • colord_dict_add_strings(&dict, "Format", format_str);
  • colord_dict_add_strings(&dict, "Colorspace", colorspace);
  • if (iccfile)
  • colord_dict_add_strings(&dict, "Filename", iccfile);
  • dbus_message_iter_close_container(&args, &dict);
  • /*
  • * Send the CreateProfile request synchronously...
  • */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)", idstr,
  •              scope);
    
  • reply = dbus_connection_send_with_reply_and_block(colord_con, message,
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (!reply)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN, "CreateProfile failed: %s:%s", error.name,
  •                error.message);
    
  • dbus_error_free(&error);
  • goto out;
  • }
  • /*
  • * Get reply data...
  • */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN,
  •                "CreateProfile failed: Incorrect reply type.");
    
  • goto out;
  • }
  • dbus_message_iter_get_basic(&args, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Created profile "%s".", profile_path);
  • cupsArrayAdd(profiles, strdup(profile_path));

+out:
+

  • if (message)
  • dbus_message_unref(message);
  • if (reply)
  • dbus_message_unref(reply);
  • if (idstr)
  • free(idstr);
    +}

+/*

  • * 'colord_delete_device()' - Delete a device
  • */
    +
    +static void
    +colord_delete_device(
  • const char device_id) / I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • char device_path; / Device object path */
  • /*
  • * Find the device...
  • */
  • if ((device_path = colord_find_device(device_id)) == NULL)
  • goto out;
  • /*
  • * Delete the device...
  • */
  • message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "DeleteDevice");
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /*
  • * Send the DeleteDevice request synchronously...
  • */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(colord_con, message,
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (!reply)
  • {
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "DeleteDevice failed: %s:%s", error.name,
  •                error.message);
    
  • dbus_error_free(&error);
  • goto out;
  • }

+out:
+

  • if (device_path)
  • free(device_path);
  • if (message)
  • dbus_message_unref(message);
  • if (reply)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colord_device_add_profile()' - Assign a profile to a device.
  • */
    +
    +static void
    +colord_device_add_profile(
  • const char device_path, / I - Device object path */
  • const char profile_path, / I - Profile object path */
  • const char relation) / I - Device relation, either
  •                      'soft' or 'hard' */
    
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • message = COLORD_DBUS_MSG(device_path, "AddProfile");
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling %s:AddProfile(%s) [%s]",
  •              device_path, profile_path, relation);
    
  • /*
  • * Send the AddProfile request synchronously...
  • */
  • dbus_error_init(&error);
  • reply = dbus_connection_send_with_reply_and_block(colord_con, message,
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (!reply)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN, "AddProfile failed: %s:%s", error.name,
  •                error.message);
    
  • dbus_error_free(&error);
  • goto out;
  • }

+out:
+

  • if (message)
  • dbus_message_unref(message);
  • if (reply)
  • dbus_message_unref(reply);
    +}

+/*

  • * 'colord_dict_add_strings()' - Add two strings to a dictionary.
  • */
    +
    +static void
    +colord_dict_add_strings(
  • DBusMessageIter dict, / I - Dictionary */
  • const char key, / I - Key string */
  • const char value) / I - Value string */
    +{
  • DBusMessageIter entry; /* Entry to add */
  • dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
  • dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
  • dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
  • dbus_message_iter_close_container(dict, &entry);
    +}

+/*

  • * 'colord_find_device()' - Finds a device
  • /
    +
    +static char * /
    O - Device path or NULL */
    +colord_find_device(
  • const char device_id) / I - Device ID string */
    +{
  • DBusMessage message = NULL; / D-Bus request */
  • DBusMessage reply = NULL; / D-Bus reply */
  • DBusMessageIter args; /* D-Bus method arguments */
  • DBusError error; /* D-Bus error */
  • const char device_path_tmp; / Device object path */
  • char device_path = NULL; / Device object path */
  • message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "FindDeviceById");
  • dbus_message_iter_init_append(message, &args);
  • dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
  • /*
  • * Send the FindDeviceById request synchronously...
  • */
  • dbus_error_init(&error);
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById(%s)", device_id);
  • reply = dbus_connection_send_with_reply_and_block(colord_con, message,
  •                                                COLORD_DBUS_TIMEOUT,
    
  •                                                &error);
    
  • if (!reply)
  • {
  • cupsdLogMessage(CUPSD_LOG_DEBUG, "FindDeviceById failed: %s:%s",
  •       error.name, error.message);
    
  • dbus_error_free(&error);
  • goto out;
  • }
  • /*
  • * Get reply data...
  • */
  • dbus_message_iter_init(reply, &args);
  • if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
  • {
  • cupsdLogMessage(CUPSD_LOG_WARN,
  •                "FindDeviceById failed: Incorrect reply type.");
    
  • goto out;
  • }
  • dbus_message_iter_get_basic(&args, &device_path_tmp);
  • if (device_path_tmp)
  • device_path = strdup(device_path_tmp);

+out:
+

  • if (message)
  • dbus_message_unref(message);
  • if (reply)
  • dbus_message_unref(reply);
  • return (device_path);
    +}

+/*

  • * 'colord_get_qualifier_format()' - Get the qualifier format.
  • * Note: Returns a value of "ColorSpace.MediaType.Resolution" by default.
  • */
    +
    +static void
    +colord_get_qualifier_format(
  • ppd_file_t ppd, / I - PPD file data */
  • char format[3]) / I - Format tuple */
    +{
  • const char tmp; / Temporary string */
  • ppd_attr_t attr; / Profile attributes */
  • /*
  • * Get 1st section...
  • */
  • if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL)
  • tmp = attr->value;
  • else if (ppdFindAttr(ppd, "DefaultColorModel", NULL))
  • tmp = "ColorModel";
  • else if (ppdFindAttr(ppd, "DefaultColorSpace", NULL))
  • tmp = "ColorSpace";
  • else
  • tmp = ""
  • format[0] = strdup(tmp);
  • /*
  • * Get 2nd section...
  • */
  • if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL)
  • tmp = attr->value;
  • else
  • tmp = "MediaType";
  • format[1] = strdup(tmp);
  • /*
  • * Get 3rd section...
  • */
  • if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL)
  • tmp = attr->value;
  • else
  • tmp = "Resolution";
  • format[2] = strdup(tmp);
    +}

+/*

  • * 'colord_register_printer()' - Register profiles for a printer.
  • */
    +
    +static void
    +colord_register_printer(
  • cupsd_printer_t p) / I - printer */
    +{
  • char ppdfile[1024], /* PPD filename */
  •   iccfile[1024];      /\* ICC filename */
    
  • ppd_file_t ppd; / PPD file */
  • cups_array_t profiles; / Profile paths array */
  • ppd_attr_t attr; / Profile attributes */
  • const char device_colorspace; / Device colorspace */
  • char format[3]; / Qualifier format tuple */
  • /*
  • * Ensure we have a D-Bus connection...
  • */
  • if (!colord_con)
  • return;
  • /*
  • * Try opening the PPD file for this printer...
  • */
  • snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
  • if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL)
  • return;
  • /*
  • * Find out the qualifier format
  • */
  • colord_get_qualifier_format(ppd, format);
  • /*
  • * See if we have any embedded profiles...
  • */
  • profiles = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup,
  •          (cups_afree_func_t)free);
    
  • for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
  •   attr;
    
  •   attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
    
  • if (attr->spec[0] && attr->value && attr->value[0])
  • {
  •  if (attr->value[0] != '/')
    
  •    snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
    
  •             attr->value);
    
  •  else
    
  •    strlcpy(iccfile, attr->value, sizeof(iccfile));
    
  •  if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser,
    
  •        cupsdLogFCMessage, p))
    
  • continue;
  •  colord_create_profile(profiles, p->name, attr->spec, COLORD_SPACE_UNKNOWN,
    
  •           format, iccfile, COLORD_SCOPE_TEMP);
    
  • }
  • /*
  • * Add the grayscale profile first. We always have a grayscale profile.
  • */
  • colord_create_profile(profiles, p->name, "Gray..", COLORD_SPACE_GRAY,
  •                    format, NULL, COLORD_SCOPE_TEMP);
    
  • /*
  • * Then add the RGB/CMYK/DeviceN color profile...
  • */
  • device_colorspace = "unknown";
  • switch (ppd->colorspace)
  • {
  • case PPD_CS_RGB :
  • case PPD_CS_CMY :
  •    device_colorspace = COLORD_SPACE_RGB;
    
  •    colord_create_profile(profiles, p->name, "RGB..", COLORD_SPACE_RGB,
    
  •             format, NULL, COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_RGBK :
  • case PPD_CS_CMYK :
  •    device_colorspace = COLORD_SPACE_CMYK;
    
  •    colord_create_profile(profiles, p->name, "CMYK..", COLORD_SPACE_CMYK,
    
  •                          format, NULL, COLORD_SCOPE_TEMP);
    
  •    break;
    
  • case PPD_CS_GRAY :
  •    device_colorspace = COLORD_SPACE_GRAY;
    
  •    break;
    
  • case PPD_CS_N :
  •    colord_create_profile(profiles, p->name, "DeviceN..",
    
  •                          COLORD_SPACE_UNKNOWN, format, NULL,
    
  •             COLORD_SCOPE_TEMP);
    
  •    break;
    
  • }
  • /*
  • * Register the device with colord.
  • */
  • cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for "%s".",
  •              p->name);
    
  • colord_create_device(p, ppd, profiles, device_colorspace, format,
  •          COLORD_RELATION_SOFT, COLORD_SCOPE_TEMP);
    
  • /*
  • * Free any memory we used...
  • */
  • cupsArrayDelete(profiles);
  • free(format[0]);
  • free(format[1]);
  • free(format[2]);
  • ppdClose(ppd);
    +}

+/*

  • * 'colord_unregister_printer()' - Unregister profiles for a printer.
  • */
    +
    +static void
    +colord_unregister_printer(
  • cupsd_printer_t p) / I - printer */
    +{
  • char device_id[1024]; /* Device ID as understood by colord */
  • /*
  • * Ensure we have a D-Bus connection...
  • */
  • if (!colord_con)
  • return;
  • /*
  • * Just delete the device itself, and leave the profiles registered
  • */
  • snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
  • colord_delete_device(device_id);
    +}
    #endif /* APPLE */
Collaborator

michaelrsweet commented May 23, 2012

"str3808p2.patch":

Index: scheduler/colorman.c

--- scheduler/colorman.c (revision 10492)
+++ scheduler/colorman.c (working copy)
@@ -166,7 +166,15 @@
cupsdStartColor(void)
{
#if !defined(APPLE) && defined(HAVE_DBUS)

  • cupsd_printer_t p; / Current printer */

colord_con = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+

  • for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
  •   p;
    
  •   p = (cupsd_printer_t *)cupsArrayNext(Printers))
    
  • cupsdRegisterColor(p);
    #endif /* !APPLE && HAVE_DBUS */
    }

michaelrsweet added this to the Stable milestone Mar 17, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment