From 65608e0f8bbc0190cc1b7646f653e796c807f02b Mon Sep 17 00:00:00 2001 From: Remi Collet Date: Tue, 27 Dec 2011 16:50:50 +0100 Subject: import cups from F16 --- cups-icc.patch | 1042 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1042 insertions(+) create mode 100644 cups-icc.patch (limited to 'cups-icc.patch') 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 +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 ++#include ++ ++/* ++ * 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 + #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 + -- cgit