From ba9bc8eeab8cd8bceb326ab3af8b8f6f69ecd39b Mon Sep 17 00:00:00 2001 From: Tim Waugh Date: Thu, 6 Jan 2011 16:21:12 +0000 Subject: [PATCH] Test patch for ICC support added but not applied by default. --- cups-icc.patch | 1741 ++++++++++++++++++++++++++++++++++++++++++++++++ cups.spec | 6 + 2 files changed, 1747 insertions(+) create mode 100644 cups-icc.patch diff --git a/cups-icc.patch b/cups-icc.patch new file mode 100644 index 0000000..f6275bd --- /dev/null +++ b/cups-icc.patch @@ -0,0 +1,1741 @@ +diff -up cups-1.4.6/scheduler/ipp.c.icc cups-1.4.6/scheduler/ipp.c +--- cups-1.4.6/scheduler/ipp.c.icc 2011-01-11 15:23:38.318062917 +0000 ++++ cups-1.4.6/scheduler/ipp.c 2011-01-11 15:23:38.379057153 +0000 +@@ -32,10 +32,6 @@ + * based upon the printer state... + * add_queued_job_count() - Add the "queued-job-count" attribute for the + * specified printer or class. +- * apple_init_profile() - Initialize a color profile. +- * apple_register_profiles() - Register color profiles for a printer. +- * apple_unregister_profiles() - Remove color profiles for the specified +- * printer. + * apply_printer_defaults() - Apply printer default options to a job. + * authenticate_job() - Set job authentication info. + * cancel_all_jobs() - Cancel all print jobs. +@@ -107,11 +103,9 @@ + */ + + #include "cupsd.h" +-#include + + #ifdef __APPLE__ + # include +-# include + # ifdef HAVE_MEMBERSHIP_H + # include + # endif /* HAVE_MEMBERSHIP_H */ +@@ -142,14 +136,6 @@ static void add_printer(cupsd_client_t * + static void add_printer_state_reasons(cupsd_client_t *con, + cupsd_printer_t *p); + static void add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p); +-#ifdef __APPLE__ +-static void apple_init_profile(ppd_file_t *ppd, cups_array_t *languages, +- CMDeviceProfileInfo *profile, unsigned id, +- const char *name, const char *text, +- const char *iccfile); +-static void apple_register_profiles(cupsd_printer_t *p); +-static void apple_unregister_profiles(cupsd_printer_t *p); +-#endif /* __APPLE__ */ + static void apply_printer_defaults(cupsd_printer_t *printer, + cupsd_job_t *job); + static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri); +@@ -2947,17 +2933,15 @@ add_printer(cupsd_client_t *con, /* I - + + cupsdSetPrinterReasons(printer, "none"); + +-#ifdef __APPLE__ + /* + * (Re)register color profiles... + */ + + if (!RunUser) + { +- apple_unregister_profiles(printer); +- apple_register_profiles(printer); ++ cupsdUnregisterColorProfiles(printer); ++ cupsdRegisterColorProfiles(printer); + } +-#endif /* __APPLE__ */ + } + + /* +@@ -3093,553 +3077,6 @@ add_queued_job_count( + } + + +-#ifdef __APPLE__ +-/* +- * 'apple_init_profile()' - Initialize a color profile. +- */ +- +-static void +-apple_init_profile( +- ppd_file_t *ppd, /* I - PPD file */ +- cups_array_t *languages, /* I - Languages in the PPD file */ +- CMDeviceProfileInfo *profile, /* I - Profile record */ +- unsigned id, /* I - Profile ID */ +- const char *name, /* I - Profile name */ +- const char *text, /* I - Profile UI text */ +- const char *iccfile) /* I - ICC filename */ +-{ +- char url[1024]; /* URL for profile filename */ +- CFMutableDictionaryRef dict; /* Dictionary for name */ +- char *language; /* Current language */ +- ppd_attr_t *attr; /* Profile attribute */ +- CFStringRef cflang, /* Language string */ +- cftext; /* Localized text */ +- +- +- /* +- * Build the profile name dictionary... +- */ +- +- dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, +- &kCFTypeDictionaryKeyCallBacks, +- &kCFTypeDictionaryValueCallBacks); +- +- cftext = CFStringCreateWithCString(kCFAllocatorDefault, text, +- kCFStringEncodingUTF8); +- +- if (cftext) +- { +- CFDictionarySetValue(dict, CFSTR("en"), cftext); +- CFRelease(cftext); +- } +- +- if (languages) +- { +- /* +- * Find localized names for the color profiles... +- */ +- +- cupsArraySave(ppd->sorted_attrs); +- +- for (language = (char *)cupsArrayFirst(languages); +- language; +- language = (char *)cupsArrayNext(languages)) +- { +- if (iccfile) +- { +- if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name, +- language)) == NULL) +- attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language); +- } +- else +- attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language); +- +- if (attr && attr->text[0]) +- { +- cflang = CFStringCreateWithCString(kCFAllocatorDefault, language, +- kCFStringEncodingUTF8); +- cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text, +- kCFStringEncodingUTF8); +- +- if (cflang && cftext) +- CFDictionarySetValue(dict, cflang, cftext); +- +- if (cflang) +- CFRelease(cflang); +- +- if (cftext) +- CFRelease(cftext); +- } +- } +- +- cupsArrayRestore(ppd->sorted_attrs); +- } +- +- /* +- * Fill in the profile data... +- */ +- +- if (iccfile) +- httpAssembleURI(HTTP_URI_CODING_ALL, url, sizeof(url), "file", NULL, "", 0, +- iccfile); +- +- profile->dataVersion = cmDeviceProfileInfoVersion1; +- profile->profileID = id; +- profile->profileLoc.locType = iccfile ? cmPathBasedProfile : cmNoProfileBase; +- profile->profileName = dict; +- +- if (iccfile) +- strlcpy(profile->profileLoc.u.pathLoc.path, iccfile, +- sizeof(profile->profileLoc.u.pathLoc.path)); +-} +- +- +-/* +- * 'apple_register_profiles()' - Register color profiles for a printer. +- */ +- +-static void +-apple_register_profiles( +- cupsd_printer_t *p) /* I - Printer */ +-{ +- int i; /* Looping var */ +- char ppdfile[1024], /* PPD filename */ +- iccfile[1024], /* ICC filename */ +- selector[PPD_MAX_NAME]; +- /* Profile selection string */ +- ppd_file_t *ppd; /* PPD file */ +- ppd_attr_t *attr, /* Profile attributes */ +- *profileid_attr,/* cupsProfileID attribute */ +- *q1_attr, /* ColorModel (or other) qualifier */ +- *q2_attr, /* MediaType (or other) qualifier */ +- *q3_attr; /* Resolution (or other) qualifier */ +- char q_keyword[PPD_MAX_NAME]; +- /* Qualifier keyword */ +- 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 */ +- CMError error; /* Last error */ +- unsigned device_id, /* Printer device ID */ +- profile_id, /* Profile ID */ +- default_profile_id = 0; +- /* Default profile ID */ +- CFMutableDictionaryRef device_name; /* Printer device name dictionary */ +- CFStringRef printer_name; /* Printer name string */ +- CMDeviceScope scope = /* Scope of the registration */ +- { +- kCFPreferencesAnyUser, +- kCFPreferencesCurrentHost +- }; +- CMDeviceProfileArrayPtr profiles; /* Profiles */ +- CMDeviceProfileInfo *profile; /* Current profile */ +- cups_array_t *languages; /* Languages array */ +- +- +- /* +- * Make sure ColorSync is available... +- */ +- +- if (CMRegisterColorDevice == 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) +- return; +- +- /* +- * 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)) +- 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)) +- continue; +- +- num_profiles ++; +- } +- +- +- /* +- * If we have profiles, add them... +- */ +- +- if (num_profiles > 0) +- { +- if (profile_key[0] == 'A') +- { +- /* +- * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile +- * attribute... +- */ +- +- if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL && +- attr->value) +- default_profile_id = atoi(attr->value); +- +- q1_choice = q2_choice = q3_choice = NULL; +- } +- else +- { +- /* +- * For CUPS PPDs, figure out the default profile selector values... +- */ +- +- 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 (q1_attr && q1_attr->value && q1_attr->value[0]) +- q1_choice = q1_attr->value; +- else +- q1_choice = ""; +- +- 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 (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; +- } +- +- /* +- * Build the array of profiles... +- * +- * Note: This calloc actually requests slightly more memory than needed. +- */ +- +- if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) +- { +- cupsdLogMessage(CUPSD_LOG_ERROR, +- "Unable to allocate memory for %d profiles!", +- num_profiles); +- ppdClose(ppd); +- return; +- } +- +- profiles->profileCount = num_profiles; +- languages = _ppdGetLanguages(ppd); +- +- for (profile = profiles->profiles, +- attr = ppdFindAttr(ppd, profile_key, NULL); +- attr; +- attr = ppdFindNextAttr(ppd, profile_key, NULL)) +- if (attr->spec[0] && attr->value && attr->value[0]) +- { +- /* +- * Add this profile... +- */ +- +- 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)) +- continue; +- +- if (profile_key[0] == 'c') +- { +- 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); +- } +- else +- profile_id = atoi(attr->spec); +- +- apple_init_profile(ppd, languages, profile, profile_id, attr->spec, +- attr->text[0] ? attr->text : attr->spec, iccfile); +- +- profile ++; +- +- /* +- * See if this is the default profile... +- */ +- +- if (!default_profile_id) +- { +- if (q2_choice) +- { +- if (q3_choice) +- { +- snprintf(selector, sizeof(selector), "%s.%s.%s", +- q1_choice, q2_choice, q3_choice); +- if (!strcmp(selector, attr->spec)) +- default_profile_id = profile_id; +- } +- +- if (!default_profile_id) +- { +- snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, +- q2_choice); +- if (!strcmp(selector, attr->spec)) +- default_profile_id = profile_id; +- } +- } +- +- if (!default_profile_id && q3_choice) +- { +- snprintf(selector, sizeof(selector), "%s..%s", q1_choice, +- q3_choice); +- if (!strcmp(selector, attr->spec)) +- default_profile_id = profile_id; +- } +- +- if (!default_profile_id) +- { +- snprintf(selector, sizeof(selector), "%s..", q1_choice); +- if (!strcmp(selector, attr->spec)) +- default_profile_id = profile_id; +- } +- } +- } +- +- _ppdFreeLanguages(languages); +- } +- else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL) +- { +- /* +- * Extract profiles from ColorModel option... +- */ +- +- const char *profile_name; /* Name of generic profile */ +- +- +- num_profiles = cm_option->num_choices; +- +- if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) +- { +- cupsdLogMessage(CUPSD_LOG_ERROR, +- "Unable to allocate memory for %d profiles!", +- num_profiles); +- ppdClose(ppd); +- return; +- } +- +- profiles->profileCount = num_profiles; +- +- for (profile = profiles->profiles, i = cm_option->num_choices, +- cm_choice = cm_option->choices; +- i > 0; +- i --, cm_choice ++, profile ++) +- { +- if (!strcmp(cm_choice->choice, "Gray") || +- !strcmp(cm_choice->choice, "Black")) +- profile_name = "Gray"; +- else if (!strcmp(cm_choice->choice, "RGB") || +- !strcmp(cm_choice->choice, "CMY")) +- profile_name = "RGB"; +- else if (!strcmp(cm_choice->choice, "CMYK") || +- !strcmp(cm_choice->choice, "KCMY")) +- profile_name = "CMYK"; +- else +- profile_name = "DeviceN"; +- +- snprintf(selector, sizeof(selector), "%s..", profile_name); +- profile_id = _ppdHashName(selector); +- +- apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, +- cm_choice->text, NULL); +- +- if (cm_choice->marked) +- default_profile_id = profile_id; +- } +- } +- else +- { +- /* +- * Use the default colorspace... +- */ +- +- attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); +- +- num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2; +- +- if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) +- { +- cupsdLogMessage(CUPSD_LOG_ERROR, +- "Unable to allocate memory for %d profiles!", +- num_profiles); +- ppdClose(ppd); +- return; +- } +- +- profiles->profileCount = num_profiles; +- +- apple_init_profile(ppd, NULL, profiles->profiles, _ppdHashName("Gray.."), +- "Gray", "Gray", NULL); +- +- switch (ppd->colorspace) +- { +- case PPD_CS_RGB : +- case PPD_CS_CMY : +- apple_init_profile(ppd, NULL, profiles->profiles + 1, +- _ppdHashName("RGB.."), "RGB", "RGB", NULL); +- break; +- case PPD_CS_RGBK : +- case PPD_CS_CMYK : +- apple_init_profile(ppd, NULL, profiles->profiles + 1, +- _ppdHashName("CMYK.."), "CMYK", "CMYK", NULL); +- break; +- +- case PPD_CS_GRAY : +- if (attr) +- break; +- +- case PPD_CS_N : +- apple_init_profile(ppd, NULL, profiles->profiles + 1, +- _ppdHashName("DeviceN.."), "DeviceN", "DeviceN", +- NULL); +- break; +- } +- } +- +- if (num_profiles > 0) +- { +- /* +- * Make sure we have a default profile ID... +- */ +- +- if (!default_profile_id) +- default_profile_id = profiles->profiles[num_profiles - 1].profileID; +- +- /* +- * Get the device ID hash and pathelogical name dictionary. +- */ +- +- cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"", +- p->name); +- +- device_id = _ppdHashName(p->name); +- device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, +- &kCFTypeDictionaryKeyCallBacks, +- &kCFTypeDictionaryValueCallBacks); +- printer_name = CFStringCreateWithCString(kCFAllocatorDefault, +- p->name, kCFStringEncodingUTF8); +- +- if (device_name && printer_name) +- { +- CFDictionarySetValue(device_name, CFSTR("en"), printer_name); +- +- /* +- * Register the device with ColorSync... +- */ +- +- error = CMRegisterColorDevice(cmPrinterDeviceClass, device_id, +- device_name, &scope); +- +- /* +- * Register the profiles... +- */ +- +- if (error == noErr) +- error = CMSetDeviceFactoryProfiles(cmPrinterDeviceClass, device_id, +- default_profile_id, profiles); +- } +- else +- error = 1000; +- +- /* +- * Clean up... +- */ +- +- if (error != noErr) +- cupsdLogMessage(CUPSD_LOG_ERROR, +- "Unable to register ICC color profiles for \"%s\" - %d", +- p->name, (int)error); +- +- for (profile = profiles->profiles; +- num_profiles > 0; +- profile ++, num_profiles --) +- CFRelease(profile->profileName); +- +- free(profiles); +- +- if (printer_name) +- CFRelease(printer_name); +- +- if (device_name) +- CFRelease(device_name); +- } +- +- ppdClose(ppd); +-} +- +- +-/* +- * 'apple_unregister_profiles()' - Remove color profiles for the specified +- * printer. +- */ +- +-static void +-apple_unregister_profiles( +- cupsd_printer_t *p) /* I - Printer */ +-{ +- /* +- * Make sure ColorSync is available... +- */ +- +- if (CMUnregisterColorDevice != NULL) +- CMUnregisterColorDevice(cmPrinterDeviceClass, _ppdHashName(p->name)); +-} +-#endif /* __APPLE__ */ +- + /* + * 'apply_printer_defaults()' - Apply printer default options to a job. + */ +@@ -6532,7 +5969,7 @@ delete_printer(cupsd_client_t *con, /* + * Unregister color profiles... + */ + +- apple_unregister_profiles(printer); ++ cupsdUnregisterColorProfiles(printer); + #endif /* __APPLE__ */ + + if (dtype & CUPS_PRINTER_CLASS) +diff -up cups-1.4.6/scheduler/printers.c.icc cups-1.4.6/scheduler/printers.c +--- cups-1.4.6/scheduler/printers.c.icc 2011-01-11 15:23:38.364058569 +0000 ++++ cups-1.4.6/scheduler/printers.c 2011-01-11 15:23:38.389056205 +0000 +@@ -40,6 +40,14 @@ + * cupsdValidateDest() - Validate a printer/class destination. + * cupsdWritePrintcap() - Write a pseudo-printcap file for older + * applications that need it... ++ * apple_init_profile() - Initialize a color profile. ++ * dbus_create_profile() - Initialise a color profile. ++ * dbus_create_device() - Initialise a color device. ++ * cupsdRegisterColorProfiles() ++ * - Register color profiles for a printer. ++ * cupsdUnregisterColorProfiles() ++ * - Remove color profiles for the specified ++ * printer. + * add_printer_defaults() - Add name-default attributes to the printer + * attributes. + * add_printer_filter() - Add a MIME filter for a printer. +@@ -64,10 +72,14 @@ + */ + + #include "cupsd.h" ++#include + #include + #ifdef HAVE_APPLICATIONSERVICES_H + # include + #endif /* HAVE_APPLICATIONSERVICES_H */ ++#ifdef __APPLE__ ++# include ++#endif /* __APPLE__ */ + #ifdef HAVE_SYS_MOUNT_H + # include + #endif /* HAVE_SYS_MOUNT_H */ +@@ -81,6 +93,16 @@ + # include + #endif /* HAVE_SYS_VFS_H */ + ++#ifdef HAVE_DBUS ++# include ++# ifdef HAVE_DBUS_MESSAGE_ITER_INIT_APPEND ++# define dbus_message_append_iter_init dbus_message_iter_init_append ++# define dbus_message_iter_append_string(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &(v)) ++# define dbus_message_iter_append_object_path(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_OBJECT_PATH, &(v)) ++# define dbus_message_iter_append_uint32(i,v) dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &(v)) ++# endif /* HAVE_DBUS_MESSAGE_ITER_INIT_APPEND */ ++#endif /* HAVE_DBUS */ ++ + + /* + * Local functions... +@@ -102,6 +124,12 @@ static void write_irix_config(cupsd_prin + static void write_irix_state(cupsd_printer_t *p); + #endif /* __sgi */ + static void write_xml_string(cups_file_t *fp, const char *s); ++#ifdef __APPLE__ ++static void apple_init_profile(ppd_file_t *ppd, cups_array_t *languages, ++ CMDeviceProfileInfo *profile, unsigned id, ++ const char *name, const char *text, ++ const char *iccfile); ++#endif /* __APPLE__ */ + + + /* +@@ -786,6 +814,14 @@ cupsdDeletePrinter( + update ? "Job stopped due to printer being deleted." : + "Job stopped."); + ++#ifdef HAVE_DBUS ++ /* ++ * Unregister the color profiles ++ */ ++ ++ cupsdUnregisterColorProfiles(p); ++#endif /* HAVE_DBUS */ ++ + /* + * If this printer is the next for browsing, point to the next one... + */ +@@ -1533,6 +1569,14 @@ cupsdRenamePrinter( + mimeDeleteType(MimeDatabase, p->prefiltertype); + p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name); + ++#ifdef HAVE_DBUS ++ /* ++ * Unregister the color profiles ++ */ ++ ++ cupsdUnregisterColorProfiles(p); ++#endif /* HAVE_DBUS */ ++ + /* + * Rename the printer... + */ +@@ -2722,6 +2766,14 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p) + write_irix_state(p); + #endif /* __sgi */ + ++#ifdef HAVE_DBUS ++ /* ++ * (Re-)register the color profiles ++ */ ++ cupsdUnregisterColorProfiles(p); ++ cupsdRegisterColorProfiles(p); ++#endif /* HAVE_DBUS */ ++ + /* + * Let the browse protocols reflect the change + */ +@@ -5576,6 +5628,996 @@ write_xml_string(cups_file_t *fp, /* I - + } + + ++#ifdef __APPLE__ ++/* ++ * 'apple_init_profile()' - Initialize a color profile. ++ */ ++ ++static void ++apple_init_profile( ++ ppd_file_t *ppd, /* I - PPD file */ ++ cups_array_t *languages, /* I - Languages in the PPD file */ ++ CMDeviceProfileInfo *profile, /* I - Profile record */ ++ unsigned id, /* I - Profile ID */ ++ const char *name, /* I - Profile name */ ++ const char *text, /* I - Profile UI text */ ++ const char *iccfile) /* I - ICC filename */ ++{ ++ char url[1024]; /* URL for profile filename */ ++ CFMutableDictionaryRef dict; /* Dictionary for name */ ++ char *language; /* Current language */ ++ ppd_attr_t *attr; /* Profile attribute */ ++ CFStringRef cflang, /* Language string */ ++ cftext; /* Localized text */ ++ ++ ++ /* ++ * Build the profile name dictionary... ++ */ ++ ++ dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, ++ &kCFTypeDictionaryKeyCallBacks, ++ &kCFTypeDictionaryValueCallBacks); ++ ++ cftext = CFStringCreateWithCString(kCFAllocatorDefault, text, ++ kCFStringEncodingUTF8); ++ ++ if (cftext) ++ { ++ CFDictionarySetValue(dict, CFSTR("en"), cftext); ++ CFRelease(cftext); ++ } ++ ++ if (languages) ++ { ++ /* ++ * Find localized names for the color profiles... ++ */ ++ ++ cupsArraySave(ppd->sorted_attrs); ++ ++ for (language = (char *)cupsArrayFirst(languages); ++ language; ++ language = (char *)cupsArrayNext(languages)) ++ { ++ if (iccfile) ++ { ++ if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name, ++ language)) == NULL) ++ attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language); ++ } ++ else ++ attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language); ++ ++ if (attr && attr->text[0]) ++ { ++ cflang = CFStringCreateWithCString(kCFAllocatorDefault, language, ++ kCFStringEncodingUTF8); ++ cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text, ++ kCFStringEncodingUTF8); ++ ++ if (cflang && cftext) ++ CFDictionarySetValue(dict, cflang, cftext); ++ ++ if (cflang) ++ CFRelease(cflang); ++ ++ if (cftext) ++ CFRelease(cftext); ++ } ++ } ++ ++ cupsArrayRestore(ppd->sorted_attrs); ++ } ++ ++ /* ++ * Fill in the profile data... ++ */ ++ ++ if (iccfile) ++ httpAssembleURI(HTTP_URI_CODING_ALL, url, sizeof(url), "file", NULL, "", 0, ++ iccfile); ++ ++ profile->dataVersion = cmDeviceProfileInfoVersion1; ++ profile->profileID = id; ++ profile->profileLoc.locType = iccfile ? cmPathBasedProfile : cmNoProfileBase; ++ profile->profileName = dict; ++ ++ if (iccfile) ++ strlcpy(profile->profileLoc.u.pathLoc.path, iccfile, ++ sizeof(profile->profileLoc.u.pathLoc.path)); ++} ++#endif /* __APPLE__ */ ++ ++ ++#if !defined(__APPLE__) && defined(HAVE_DBUS) ++/* ++ * 'dbus_create_profile()' - Create a color profile for a printer. ++ */ ++ ++static void ++dbus_create_profile (cups_array_t *profiles, /* I - Profiles array */ ++ DBusConnection *con, /* I - D-Bus connection */ ++ const char *printer_name, /* I - Printer name */ ++ const char *qualifier, /* I - Profile qualifier */ ++ const char *iccfile) /* I - ICC filename */ ++{ ++ DBusMessage *message; /* D-Bus message */ ++ DBusMessageIter args; /* D-Bus method arguments */ ++ DBusPendingCall *pending; /* D-Bus method call */ ++ char *path = NULL; /* Profile path */ ++ char *idstr; /* Profile ID string */ ++ size_t idstrlen; /* Profile ID allocated length */ ++ int options = 1; /* Options for CreateProfile */ ++ ++ /* ++ * Create the profile... ++ */ ++ ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ "/org/freedesktop/ColorManager", ++ "org.freedesktop.ColorManager", ++ "CreateProfile"); ++ ++ dbus_message_append_iter_init(message, &args); ++ idstrlen = strlen (printer_name) + 1 + strlen (qualifier) + 1; ++ idstr = malloc (idstrlen); ++ if (!idstr) ++ goto out; ++ ++ snprintf (idstr, idstrlen, "%s-%s", printer_name, qualifier); ++ dbus_message_iter_append_string(&args, idstr); ++ dbus_message_iter_append_uint32(&args, options); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%d)", ++ idstr, options); ++ if (!dbus_connection_send_with_reply(con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++ message = dbus_pending_call_steal_reply(pending); ++// dbus_pending_call_unref(pending); <-fixme ++ ++ if (!message || ++ !dbus_message_iter_init(message, &args) || ++ dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) ++ goto out; ++ ++ dbus_message_iter_get_basic(&args, &path); ++ path = strdup(path); ++ cupsArrayAdd(profiles, strdup(path)); ++ ++ /* ++ * Set the qualifier... ++ */ ++ ++ dbus_message_unref(message); ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ path, ++ "org.freedesktop.ColorManager.Profile", ++ "SetQualifier"); ++ dbus_message_append_iter_init(message, &args); ++ dbus_message_iter_append_string(&args, qualifier); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling SetQualifier(%s)", qualifier); ++ if (!dbus_connection_send_with_reply(con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++ message = dbus_pending_call_steal_reply(pending); ++ dbus_pending_call_unref(pending); ++ ++ /* ++ * If we know the ICC file for it, set that now... ++ */ ++ ++ if (!iccfile) ++ goto out; ++ ++ dbus_message_unref(message); ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ path, ++ "org.freedesktop.ColorManager.Profile", ++ "SetFilename"); ++ dbus_message_append_iter_init(message, &args); ++ dbus_message_iter_append_string(&args, iccfile); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling SetFilename(%s)", iccfile); ++ if (!dbus_connection_send_with_reply(con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++ message = dbus_pending_call_steal_reply(pending); ++ dbus_pending_call_unref(pending); ++ ++out: ++ free (path); ++ free (idstr); ++ dbus_message_unref(message); ++} ++ ++ ++/* ++ * 'dbus_create_device()' - Create a device and register profiles. ++ */ ++ ++static void ++dbus_create_device (DBusConnection *con, /* I - D-Bus connection */ ++ const char *name, /* I - Printer name */ ++ cups_array_t *profiles, /* I - Profiles array */ ++ const char *default_profile_id) /* I - Default profile */ ++{ ++ DBusMessage *message; /* D-Bus message */ ++ DBusMessageIter args; /* D-Bus method arguments */ ++ DBusPendingCall *pending; /* D-Bus method call */ ++ const char *device_path_tmp; /* Device path data */ ++ char *device_path = NULL; /* Device path */ ++ const char *profile_path; /* Profile path */ ++ char *default_profile_path = NULL; ++ /* Default profile path */ ++ size_t default_path_len; ++ /* Length of profile path */ ++ int options = 1; /* Options for CreateDevice */ ++ ++ /* ++ * Create the device... ++ */ ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ "/org/freedesktop/ColorManager", ++ "org.freedesktop.ColorManager", ++ "CreateDevice"); ++ ++ dbus_message_append_iter_init(message, &args); ++ dbus_message_iter_append_string(&args, name); ++ dbus_message_iter_append_uint32(&args, options); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%d)", ++ name, options); ++ if (!dbus_connection_send_with_reply (con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++ message = dbus_pending_call_steal_reply(pending); ++ dbus_pending_call_unref(pending); ++ ++ if (!message || ++ !dbus_message_iter_init(message, &args) || ++ dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) ++ goto out; ++ ++ /* get device path, and duplicate so we can free the method */ ++ dbus_message_iter_get_basic(&args, &device_path_tmp); ++ device_path = strdup (device_path_tmp); ++ dbus_message_unref(message); ++ for (profile_path = cupsArrayFirst(profiles); ++ profile_path; ++ profile_path = cupsArrayNext(profiles)) ++ { ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ device_path, ++ "org.freedesktop.ColorManager.Device", ++ "AddProfile"); ++ ++ dbus_message_append_iter_init(message, &args); ++ dbus_message_iter_append_object_path(&args, profile_path); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling AddProfile(%s)", profile_path); ++ pending = NULL; ++ if (!dbus_connection_send_with_reply (con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++// message = dbus_pending_call_steal_reply(pending); ++ dbus_pending_call_unref(pending); ++ } ++ ++ /* ++ * Set the default profile ++ */ ++ default_path_len = strlen (name) + 1 + strlen (default_profile_id) + 1; ++ default_profile_path = malloc (default_path_len); ++ if (!default_profile_path) ++ goto out; ++ ++ snprintf(default_profile_path, default_path_len, "%s-%s", name, ++ default_profile_id); ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ device_path, ++ "org.freedesktop.ColorManager.Device", ++ "MakeProfileDefault"); ++ ++ dbus_message_append_iter_init(message, &args); ++ dbus_message_iter_append_string(&args, default_profile_path); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling MakeProfileDefault(%s)", ++ default_profile_path); ++ if (!dbus_connection_send_with_reply (con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++// message = dbus_pending_call_steal_reply(pending); ++ dbus_pending_call_unref(pending); ++ ++out: ++ free(default_profile_path); ++ free(device_path); ++// dbus_message_unref(message); ++} ++ ++ ++/* ++ * 'dbus_delete_device_and_profiles()' - Delete previously registered ++ * color device and profiles ++ */ ++ ++static void ++dbus_delete_device_and_profiles(cupsd_printer_t *p) /* I - Printer */ ++{ ++ DBusConnection *con; /* System D-Bus connection */ ++ DBusMessage *message; /* D-Bus message */ ++ DBusMessageIter args, array_args; /* D-Bus method arguments */ ++ DBusPendingCall *pending; /* D-Bus method call */ ++ const char *device_path; /* Device path */ ++ const char *options = ""; /* Options for GetProfilesForDevice */ ++ cups_array_t *profile_paths; /* Profile paths array */ ++ char *profile_path; /* Profile path */ ++ ++ con = dbus_bus_get (DBUS_BUS_SYSTEM, NULL); ++ if (!con) ++ return; ++ ++ /* ++ * Get the device path ++ */ ++ ++ profile_paths = cupsArrayNew(NULL, NULL); ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ "/org/freedesktop/ColorManager", ++ "org.freedesktop.ColorManager", ++ "FindDeviceById"); ++ ++ dbus_message_append_iter_init(message, &args); ++ dbus_message_iter_append_string(&args, p->name); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById"); ++ if (!dbus_connection_send_with_reply(con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++ message = dbus_pending_call_steal_reply(pending); ++ dbus_pending_call_unref(pending); ++ ++ if (!message || ++ !dbus_message_iter_init(message, &args) || ++ dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) ++ goto out; ++ ++ dbus_message_iter_get_basic(&args, &device_path); ++ device_path = strdup(device_path); ++ ++ /* ++ * Get the profiles ++ */ ++ ++ dbus_message_unref(message); ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ "/org/freedesktop/ColorManager", ++ "org.freedesktop.ColorManager", ++ "GetProfilesForDevice"); ++ ++ dbus_message_append_iter_init(message, &args); ++ dbus_message_iter_append_object_path(&args, device_path); ++ dbus_message_iter_append_string(&args, options); ++ cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling GetProfilesForDevice(%s,\"\")", ++ device_path); ++ if (!dbus_connection_send_with_reply(con, message, &pending, -1)) ++ goto out; ++ ++ dbus_connection_flush(con); ++ dbus_message_unref(message); ++ dbus_pending_call_block(pending); ++ message = dbus_pending_call_steal_reply(pending); ++ dbus_pending_call_unref(pending); ++ ++ if (!message || ++ !dbus_message_iter_init(message, &args) || ++ dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) ++ goto out; ++ ++ 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); ++ cupsArrayAdd(profile_paths, strdup (profile_path)); ++ } ++ } while (dbus_message_iter_next(&array_args)); ++ ++ /* ++ * Delete each profile. ++ */ ++ ++ ++out: ++ for (profile_path = cupsArrayFirst(profile_paths); ++ profile_path; ++ profile_path = cupsArrayNext(profile_paths)) ++ free (profile_path); ++ ++ cupsArrayDelete(profile_paths); ++ dbus_message_unref(message); ++ dbus_connection_unref(con); ++} ++#endif /* !defined(__APPLE__) && defined(HAVE_DBUS) */ ++ ++ ++/* ++ * 'cupsdRegisterColorProfiles()' - Register color profiles for a printer. ++ */ ++ ++void ++cupsdRegisterColorProfiles( ++ cupsd_printer_t *p) /* I - Printer */ ++{ ++ int i; /* Looping var */ ++ char ppdfile[1024], /* PPD filename */ ++ iccfile[1024], /* ICC filename */ ++ selector[PPD_MAX_NAME]; ++ /* Profile selection string */ ++ ppd_file_t *ppd; /* PPD file */ ++ ppd_attr_t *attr, /* Profile attributes */ ++ *q1_attr, /* ColorModel (or other) qualifier */ ++ *q2_attr, /* MediaType (or other) qualifier */ ++ *q3_attr; /* Resolution (or other) qualifier */ ++ char q_keyword[PPD_MAX_NAME]; ++ /* Qualifier keyword */ ++ 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 */ ++#ifdef __APPLE__ ++ ppd_attr_t *profileid_attr;/* cupsProfileID attribute */ ++ unsigned profile_id, /* Profile ID */ ++ default_profile_id = 0; ++ /* Default profile ID */ ++ CMError error; /* Last error */ ++ CFMutableDictionaryRef device_name; /* Printer device name dictionary */ ++ unsigned device_id; /* Printer device ID */ ++ CFStringRef printer_name; /* Printer name string */ ++ CMDeviceScope scope = /* Scope of the registration */ ++ { ++ kCFPreferencesAnyUser, ++ kCFPreferencesCurrentHost ++ }; ++ CMDeviceProfileArrayPtr profiles; /* Profiles */ ++ CMDeviceProfileInfo *profile; /* Current profile */ ++ cups_array_t *languages; /* Languages array */ ++#elif HAVE_DBUS ++ const char *profile_id = NULL, ++ /* Profile ID */ ++ *default_profile_id = NULL; ++ /* Default profile ID */ ++ DBusError error; /* Error, if any */ ++ static DBusConnection *con; /* System D-Bus connection */ ++ cups_array_t *profiles; /* Profile paths array */ ++ char *profile_path; /* Profile path */ ++#endif /* HAVE_DBUS */ ++ ++ ++#ifdef __APPLE__ ++ /* ++ * Make sure ColorSync is available... ++ */ ++ ++ if (CMRegisterColorDevice == NULL) ++ return; ++#elif defined(HAVE_DBUS) ++ if (con && !dbus_connection_get_is_connected(con)) ++ { ++ dbus_connection_unref(con); ++ con = NULL; ++ } ++ ++ if (!con) ++ { ++ dbus_error_init(&error); ++ ++ con = dbus_bus_get (DBUS_BUS_SYSTEM, &error); ++ if (!con) ++ { ++ if (dbus_error_is_set(&error)) ++ cupsdLogMessage(CUPSD_LOG_DEBUG, ++ "D-Bus connection error: %s", error.message); ++ ++ dbus_error_free(&error); ++ return; ++ } ++ } ++ ++ profiles = cupsArrayNew (NULL, NULL); ++#else /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ return; ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ ++ /* ++ * Try opening the PPD file for this printer... ++ */ ++ ++ snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); ++ if ((ppd = ppdOpenFile(ppdfile)) == NULL) ++ return; ++ ++ /* ++ * 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)) ++ 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)) ++ continue; ++ ++ num_profiles ++; ++ } ++ ++ ++ /* ++ * If we have profiles, add them... ++ */ ++ ++ if (num_profiles > 0) ++ { ++ if (profile_key[0] == 'A') ++ { ++ /* ++ * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile ++ * attribute... ++ */ ++ ++ if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL && ++ attr->value) ++ { ++#ifdef __APPLE__ ++ default_profile_id = atoi(attr->value); ++#elif HAVE_DBUS ++ default_profile_id = attr->value; ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ } ++ ++ q1_choice = q2_choice = q3_choice = NULL; ++ } ++ else ++ { ++ /* ++ * For CUPS PPDs, figure out the default profile selector values... ++ */ ++ ++ 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 (q1_attr && q1_attr->value && q1_attr->value[0]) ++ q1_choice = q1_attr->value; ++ else ++ q1_choice = ""; ++ ++ 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 (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; ++ } ++ ++#ifdef __APPLE__ ++ /* ++ * Build the array of profiles... ++ * ++ * Note: This calloc actually requests slightly more memory than needed. ++ */ ++ ++ if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) ++ { ++ cupsdLogMessage(CUPSD_LOG_ERROR, ++ "Unable to allocate memory for %d profiles!", ++ num_profiles); ++ ppdClose(ppd); ++ return; ++ } ++ ++ profiles->profileCount = num_profiles; ++ languages = _ppdGetLanguages(ppd); ++ profile = profiles->profiles; ++#endif /* __APPLE__ */ ++ ++ for (attr = ppdFindAttr(ppd, profile_key, NULL); ++ attr; ++ attr = ppdFindNextAttr(ppd, profile_key, NULL)) ++ if (attr->spec[0] && attr->value && attr->value[0]) ++ { ++ /* ++ * Add this profile... ++ */ ++ ++ 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)) ++ continue; ++ ++#ifdef __APPLE__ ++ if (profile_key[0] == 'c') ++ { ++ 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); ++ } ++ else ++ profile_id = atoi(attr->spec); ++ ++ apple_init_profile(ppd, languages, profile, profile_id, attr->spec, ++ attr->text[0] ? attr->text : attr->spec, iccfile); ++ profile ++; ++#elif defined(HAVE_DBUS) ++ profile_id = attr->spec; ++ dbus_create_profile(profiles, con, p->name, attr->spec, iccfile); ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ ++ /* ++ * See if this is the default profile... ++ */ ++ ++ if (!default_profile_id) ++ { ++ if (q2_choice) ++ { ++ if (q3_choice) ++ { ++ snprintf(selector, sizeof(selector), "%s.%s.%s", ++ q1_choice, q2_choice, q3_choice); ++ if (!strcmp(selector, attr->spec)) ++ default_profile_id = profile_id; ++ } ++ ++ if (!default_profile_id) ++ { ++ snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, ++ q2_choice); ++ if (!strcmp(selector, attr->spec)) ++ default_profile_id = profile_id; ++ } ++ } ++ ++ if (!default_profile_id && q3_choice) ++ { ++ snprintf(selector, sizeof(selector), "%s..%s", q1_choice, ++ q3_choice); ++ if (!strcmp(selector, attr->spec)) ++ default_profile_id = profile_id; ++ } ++ ++ if (!default_profile_id) ++ { ++ snprintf(selector, sizeof(selector), "%s..", q1_choice); ++ if (!strcmp(selector, attr->spec)) ++ default_profile_id = profile_id; ++ } ++ } ++ } ++ ++#ifdef __APPLE__ ++ _ppdFreeLanguages(languages); ++#endif /* __APPLE__ */ ++ } ++ else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL) ++ { ++ /* ++ * Extract profiles from ColorModel option... ++ */ ++ ++ const char *profile_name; /* Name of generic profile */ ++ ++ ++ num_profiles = cm_option->num_choices; ++ ++#ifdef __APPLE__ ++ if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) ++ { ++ cupsdLogMessage(CUPSD_LOG_ERROR, ++ "Unable to allocate memory for %d profiles!", ++ num_profiles); ++ ppdClose(ppd); ++ return; ++ } ++ ++ profiles->profileCount = num_profiles; ++ profile = profiles->profiles; ++#endif /* __APPLE__ */ ++ ++ for (i = cm_option->num_choices, cm_choice = cm_option->choices; ++ i > 0; ++ i --, cm_choice ++) ++ { ++ if (!strcmp(cm_choice->choice, "Gray") || ++ !strcmp(cm_choice->choice, "Black")) ++ profile_name = "Gray"; ++ else if (!strcmp(cm_choice->choice, "RGB") || ++ !strcmp(cm_choice->choice, "CMY")) ++ profile_name = "RGB"; ++ else if (!strcmp(cm_choice->choice, "CMYK") || ++ !strcmp(cm_choice->choice, "KCMY")) ++ profile_name = "CMYK"; ++ else ++ profile_name = "DeviceN"; ++ ++ snprintf(selector, sizeof(selector), "%s..", profile_name); ++ ++#ifdef __APPLE__ ++ profile_id = _ppdHashName(selector); ++ apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, ++ cm_choice->text, NULL); ++ profile ++; ++#elif defined(HAVE_DBUS) ++ profile_id = selector; ++ dbus_create_profile(profiles, con, p->name, selector, NULL); ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ ++ if (cm_choice->marked) ++ default_profile_id = profile_id; ++ } ++ } ++ else ++ { ++ /* ++ * Use the default colorspace... ++ */ ++ ++ attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); ++ ++ num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2; ++ ++#ifdef __APPLE__ ++ if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) ++ { ++ cupsdLogMessage(CUPSD_LOG_ERROR, ++ "Unable to allocate memory for %d profiles!", ++ num_profiles); ++ ppdClose(ppd); ++ return; ++ } ++ ++ profiles->profileCount = num_profiles; ++ ++ apple_init_profile(ppd, NULL, profiles->profiles, _ppdHashName("Gray.."), ++ "Gray", "Gray", NULL); ++#elif defined(HAVE_DBUS) ++ profile_id = "Gray.."; ++ dbus_create_profile(profiles, con, p->name, profile_id, NULL); ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ ++ switch (ppd->colorspace) ++ { ++ case PPD_CS_RGB : ++ case PPD_CS_CMY : ++#ifdef __APPLE__ ++ apple_init_profile(ppd, NULL, profiles->profiles + 1, ++ _ppdHashName("RGB.."), "RGB", "RGB", NULL); ++#elif defined(HAVE_DBUS) ++ profile_id = "RGB.."; ++ dbus_create_profile(profiles, con, p->name, profile_id, NULL); ++#endif /* HAVE_DBUS */ ++ break; ++ case PPD_CS_RGBK : ++ case PPD_CS_CMYK : ++#ifdef __APPLE__ ++ apple_init_profile(ppd, NULL, profiles->profiles + 1, ++ _ppdHashName("CMYK.."), "CMYK", "CMYK", NULL); ++#elif defined(HAVE_DBUS) ++ profile_id = "CMYK.."; ++ dbus_create_profile(profiles, con, p->name, profile_id, NULL); ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ break; ++ ++ case PPD_CS_GRAY : ++ if (attr) ++ break; ++ ++ case PPD_CS_N : ++#ifdef __APPLE__ ++ apple_init_profile(ppd, NULL, profiles->profiles + 1, ++ _ppdHashName("DeviceN.."), "DeviceN", "DeviceN", ++ NULL); ++#elif defined(HAVE_DBUS) ++ profile_id = "DeviceN.."; ++ dbus_create_profile(profiles, con, p->name, profile_id, NULL); ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ ++ break; ++ } ++ } ++ ++ if (num_profiles > 0) ++ { ++ /* ++ * Make sure we have a default profile ID... ++ */ ++ ++ if (!default_profile_id) ++ { ++#ifdef __APPLE__ ++ default_profile_id = profiles->profiles[num_profiles - 1].profileID; ++#elif HAVE_DBUS ++ default_profile_id = profile_id; ++#endif /* __APPLE__ */ ++ } ++ ++ /* ++ * Get the device ID hash and pathelogical name dictionary. ++ */ ++ ++ cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"", ++ p->name); ++ ++#ifdef __APPLE__ ++ device_id = _ppdHashName(p->name); ++ ++ device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, ++ &kCFTypeDictionaryKeyCallBacks, ++ &kCFTypeDictionaryValueCallBacks); ++ printer_name = CFStringCreateWithCString(kCFAllocatorDefault, ++ p->name, kCFStringEncodingUTF8); ++ ++ if (device_name && printer_name) ++ { ++ CFDictionarySetValue(device_name, CFSTR("en"), printer_name); ++ ++ /* ++ * Register the device with ColorSync... ++ */ ++ ++ error = CMRegisterColorDevice(cmPrinterDeviceClass, device_id, ++ device_name, &scope); ++ ++ /* ++ * Register the profiles... ++ */ ++ ++ if (error == noErr) ++ error = CMSetDeviceFactoryProfiles(cmPrinterDeviceClass, device_id, ++ default_profile_id, profiles); ++ } ++ else ++ error = 1000; ++#elif defined(HAVE_DBUS) ++ dbus_create_device (con, p->name, profiles, default_profile_id); ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ ++ /* ++ * Clean up... ++ */ ++ ++#ifdef __APPLE__ ++ if (error != noErr) ++ cupsdLogMessage(CUPSD_LOG_ERROR, ++ "Unable to register ICC color profiles for \"%s\" - %d", ++ p->name, (int)error); ++ ++ for (profile = profiles->profiles; ++ num_profiles > 0; ++ profile ++, num_profiles --) ++ CFRelease(profile->profileName); ++ ++ free(profiles); ++ ++ if (printer_name) ++ CFRelease(printer_name); ++ ++ if (device_name) ++ CFRelease(device_name); ++#elif defined(HAVE_DBUS) ++ for (profile_path = cupsArrayFirst(profiles); ++ profile_path; ++ profile_path = cupsArrayNext(profiles)) ++ free (profile_path); ++ ++ cupsArrayDelete(profiles); ++ dbus_connection_flush(con); ++ ++ /* ++ * Don't unref the connection but instead keep it around for future ++ * calls (it is a local static variable). Once we disconnect from ++ * the bus all our devices and profiles will be gone. ++ */ ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++ } ++ ++ ppdClose(ppd); ++} ++ ++ ++/* ++ * 'cupsdUnregisterColorProfiles()' - Remove color profiles for the specified ++ * printer. ++ */ ++ ++void ++cupsdUnregisterColorProfiles( ++ cupsd_printer_t *p) /* I - Printer */ ++{ ++#ifdef __APPLE__ ++ /* ++ * Make sure ColorSync is available... ++ */ ++ ++ if (CMUnregisterColorDevice != NULL) ++ CMUnregisterColorDevice(cmPrinterDeviceClass, _ppdHashName(p->name)); ++#elif defined(HAVE_DBUS) ++ dbus_delete_device_and_profiles (p); ++#endif /* defined(__APPLE__) || defined(HAVE_DBUS) */ ++} ++ ++ + /* + * End of "$Id: printers.c 9313 2010-09-22 18:35:07Z mike $". + */ +diff -up cups-1.4.6/scheduler/printers.h.icc cups-1.4.6/scheduler/printers.h +--- cups-1.4.6/scheduler/printers.h.icc 2011-01-11 15:23:38.365058476 +0000 ++++ cups-1.4.6/scheduler/printers.h 2011-01-11 15:23:38.389056205 +0000 +@@ -189,6 +189,8 @@ extern const char *cupsdValidateDest(con + cups_ptype_t *dtype, + cupsd_printer_t **printer); + extern void cupsdWritePrintcap(void); ++extern void cupsdRegisterColorProfiles(cupsd_printer_t *printer); ++extern void cupsdUnregisterColorProfiles(cupsd_printer_t *printer); + + + /* diff --git a/cups.spec b/cups.spec index f1affdd..72bf0f7 100644 --- a/cups.spec +++ b/cups.spec @@ -2,6 +2,7 @@ %global php_apiver %((echo 0; php -i 2>/dev/null | sed -n 's/^PHP API => //p') | tail -1) %define use_alternatives 1 +%define icc 0 %define lspp 1 %define cups_serverbin %{_exec_prefix}/lib/cups @@ -68,6 +69,7 @@ Patch38: cups-autotype-crash.patch Patch39: cups-str3754.patch Patch40: cups-avahi.patch Patch41: cups-usb-buffer-size.patch +Patch42: cups-icc.patch Patch100: cups-lspp.patch @@ -285,6 +287,10 @@ module. %patch40 -p1 -b .avahi # Use a smaller buffer when writing to USB devices (bug #617208). %patch41 -p1 -b .usb-buffer-size +%if %icc +# ICC support (work in progress). Disable lspp for testing. +%patch42 -p1 -b .icc +%endif %if %lspp # LSPP support.