summaryrefslogtreecommitdiffstats
path: root/cups-icc.patch
diff options
context:
space:
mode:
authorRemi Collet <fedora@famillecollet.com>2011-12-27 16:50:50 +0100
committerRemi Collet <fedora@famillecollet.com>2011-12-27 16:50:50 +0100
commit65608e0f8bbc0190cc1b7646f653e796c807f02b (patch)
tree274ade8f5007bd7f9c252d8262637e0300363e82 /cups-icc.patch
import cups from F16
Diffstat (limited to 'cups-icc.patch')
-rw-r--r--cups-icc.patch1042
1 files changed, 1042 insertions, 0 deletions
diff --git a/cups-icc.patch b/cups-icc.patch
new file mode 100644
index 0000000..db4ae22
--- /dev/null
+++ b/cups-icc.patch
@@ -0,0 +1,1042 @@
+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
+