]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/colorman.c
Merge changes from CUPS 1.6svn-r10510.
[thirdparty/cups.git] / scheduler / colorman.c
1 /*
2 * "$Id$"
3 *
4 * Color management routines for the CUPS scheduler.
5 *
6 * Copyright 2007-2012 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Original DBUS/colord code is Copyright 2011 Red Hat, Inc.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 *
21 * Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 *
24 * Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Contents:
42 *
43 */
44
45 /*
46 * Include necessary headers...
47 */
48
49 #include "cupsd.h"
50 #include <cups/ppd-private.h>
51
52 #ifdef __APPLE__
53 # include <ApplicationServices/ApplicationServices.h>
54 extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id);
55 # include <CoreFoundation/CoreFoundation.h>
56 #elif defined(HAVE_DBUS)
57 # include <dbus/dbus.h>
58
59 /*
60 * Defines used by colord. See the reference docs for further details:
61 *
62 * http://colord.hughsie.com/api/ref-dbus.html
63 */
64
65 # define COLORD_SCOPE_NORMAL "normal"
66 /* System scope */
67 # define COLORD_SCOPE_TEMP "temp" /* Process scope */
68 # define COLORD_SCOPE_DISK "disk" /* Lives forever, as stored in DB */
69
70 # define COLORD_RELATION_SOFT "soft" /* Mapping is not default */
71 # define COLORD_RELATION_HARD "hard" /* Explicitly mapped profile */
72
73 # define COLORD_SPACE_RGB "rgb" /* RGB colorspace */
74 # define COLORD_SPACE_CMYK "cmyk" /* CMYK colorspace */
75 # define COLORD_SPACE_GRAY "gray" /* Gray colorspace */
76 # define COLORD_SPACE_UNKNOWN "unknown"
77 /* Unknown colorspace */
78
79 # define COLORD_MODE_PHYSICAL "physical"
80 /* Actual device */
81 # define COLORD_MODE_VIRTUAL "virtual"
82 /* Virtual device with no hardware */
83
84 # define COLORD_KIND_PRINTER "printer"
85 /* printing output device */
86
87 # define COLORD_DBUS_MSG(p,m) dbus_message_new_method_call(\
88 "org.freedesktop.ColorManager", (p),\
89 "org.freedesktop.ColorManager", (m))
90 /* Macro to make new colord messages */
91 # define COLORD_DBUS_PATH "/org/freedesktop/ColorManager"
92 /* Path for color management system */
93 # define COLORD_DBUS_TIMEOUT 5000 /* Timeout for connecting to colord in ms */
94 #endif /* __APPLE__ */
95
96
97 /*
98 * Local globals...
99 */
100
101 #if !defined(__APPLE__) && defined(HAVE_DBUS)
102 static DBusConnection *colord_con = NULL;
103 /* DBUS connection for colord */
104 #endif /* !__APPLE__ && HAVE_DBUS */
105
106
107 /*
108 * Local functions...
109 */
110
111 #ifdef __APPLE__
112 static void apple_init_profile(ppd_file_t *ppd, cups_array_t *languages,
113 CFMutableDictionaryRef profile,
114 unsigned id, const char *name,
115 const char *text, const char *iccfile);
116 static void apple_register_profiles(cupsd_printer_t *p);
117 static void apple_unregister_profiles(cupsd_printer_t *p);
118
119 #elif defined(HAVE_DBUS)
120 static void colord_create_device(cupsd_printer_t *p, ppd_file_t *ppd,
121 cups_array_t *profiles,
122 const char *colorspace, char **format,
123 const char *relation, const char *scope);
124 static void colord_create_profile(cups_array_t *profiles,
125 const char *printer_name,
126 const char *qualifier,
127 const char *colorspace,
128 char **format, const char *iccfile,
129 const char *scope);
130 static void colord_delete_device(const char *device_id);
131 static void colord_device_add_profile(const char *device_path,
132 const char *profile_path,
133 const char *relation);
134 static void colord_dict_add_strings(DBusMessageIter *dict,
135 const char *key, const char *value);
136 static char *colord_find_device(const char *device_id);
137 static void colord_get_qualifier_format(ppd_file_t *ppd, char *format[3]);
138 static void colord_register_printer(cupsd_printer_t *p);
139 static void colord_unregister_printer(cupsd_printer_t *p);
140 #endif /* __APPLE__ */
141
142
143 /*
144 * 'cupsdRegisterColor()' - Register vendor color profiles in a PPD file.
145 */
146
147 void
148 cupsdRegisterColor(cupsd_printer_t *p) /* I - Printer */
149 {
150 #ifdef __APPLE__
151 apple_unregister_profiles(p);
152 apple_register_profiles(p);
153
154 #elif defined(HAVE_DBUS)
155 colord_unregister_printer(p);
156 colord_register_printer(p);
157 #endif /* __APPLE__ */
158 }
159
160
161 /*
162 * 'cupsdStartColor()' - Initialize color management.
163 */
164
165 void
166 cupsdStartColor(void)
167 {
168 #if !defined(__APPLE__) && defined(HAVE_DBUS)
169 cupsd_printer_t *p; /* Current printer */
170
171
172 colord_con = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
173
174 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
175 p;
176 p = (cupsd_printer_t *)cupsArrayNext(Printers))
177 cupsdRegisterColor(p);
178 #endif /* !__APPLE__ && HAVE_DBUS */
179 }
180
181
182 /*
183 * 'cupsdStopColor()' - Shutdown color management.
184 */
185
186 void
187 cupsdStopColor(void)
188 {
189 #if !defined(__APPLE__) && defined(HAVE_DBUS)
190 dbus_connection_unref(colord_con);
191 colord_con = NULL;
192 #endif /* !__APPLE__ && HAVE_DBUS */
193 }
194
195
196 /*
197 * 'cupsdUnregisterColor()' - Unregister vendor color profiles in a PPD file.
198 */
199
200 void
201 cupsdUnregisterColor(cupsd_printer_t *p)/* I - Printer */
202 {
203 #ifdef __APPLE__
204 apple_unregister_profiles(p);
205
206 #elif defined(HAVE_DBUS)
207 colord_unregister_printer(p);
208 #endif /* __APPLE__ */
209 }
210
211
212 #ifdef __APPLE__
213 /*
214 * 'apple_init_profile()' - Initialize a color profile.
215 */
216
217 static void
218 apple_init_profile(
219 ppd_file_t *ppd, /* I - PPD file */
220 cups_array_t *languages, /* I - Languages in the PPD file */
221 CFMutableDictionaryRef profile, /* I - Profile dictionary */
222 unsigned id, /* I - Profile ID */
223 const char *name, /* I - Profile name */
224 const char *text, /* I - Profile UI text */
225 const char *iccfile) /* I - ICC filename */
226 {
227 CFURLRef url; /* URL for profile filename */
228 CFMutableDictionaryRef dict; /* Dictionary for name */
229 char *language; /* Current language */
230 ppd_attr_t *attr; /* Profile attribute */
231 CFStringRef cflang, /* Language string */
232 cftext; /* Localized text */
233
234
235 (void)id;
236
237 /*
238 * Build the profile name dictionary...
239 */
240
241 dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
242 &kCFTypeDictionaryKeyCallBacks,
243 &kCFTypeDictionaryValueCallBacks);
244 if (!dict)
245 {
246 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize profile \"%s\".",
247 iccfile);
248 return;
249 }
250
251 cftext = CFStringCreateWithCString(kCFAllocatorDefault, text,
252 kCFStringEncodingUTF8);
253
254 if (cftext)
255 {
256 CFDictionarySetValue(dict, CFSTR("en_US"), cftext);
257 CFRelease(cftext);
258 }
259
260 if (languages)
261 {
262 /*
263 * Find localized names for the color profiles...
264 */
265
266 cupsArraySave(ppd->sorted_attrs);
267
268 for (language = (char *)cupsArrayFirst(languages);
269 language;
270 language = (char *)cupsArrayNext(languages))
271 {
272 if (iccfile)
273 {
274 if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name,
275 language)) == NULL)
276 attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language);
277 }
278 else
279 attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language);
280
281 if (attr && attr->text[0])
282 {
283 cflang = CFStringCreateWithCString(kCFAllocatorDefault, language,
284 kCFStringEncodingUTF8);
285 cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text,
286 kCFStringEncodingUTF8);
287
288 if (cflang && cftext)
289 CFDictionarySetValue(dict, cflang, cftext);
290
291 if (cflang)
292 CFRelease(cflang);
293
294 if (cftext)
295 CFRelease(cftext);
296 }
297 }
298
299 cupsArrayRestore(ppd->sorted_attrs);
300 }
301
302 /*
303 * Fill in the profile data...
304 */
305
306 if (iccfile)
307 {
308 url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
309 (const UInt8 *)iccfile,
310 strlen(iccfile), false);
311
312 if (url)
313 {
314 CFDictionarySetValue(profile, kColorSyncDeviceProfileURL, url);
315 CFRelease(url);
316 }
317 }
318
319 CFDictionarySetValue(profile, kColorSyncDeviceModeDescriptions, dict);
320 CFRelease(dict);
321 }
322
323
324 /*
325 * 'apple_register_profiles()' - Register color profiles for a printer.
326 */
327
328 static void
329 apple_register_profiles(
330 cupsd_printer_t *p) /* I - Printer */
331 {
332 int i; /* Looping var */
333 char ppdfile[1024], /* PPD filename */
334 iccfile[1024], /* ICC filename */
335 selector[PPD_MAX_NAME];
336 /* Profile selection string */
337 ppd_file_t *ppd; /* PPD file */
338 ppd_attr_t *attr, /* Profile attributes */
339 *profileid_attr,/* cupsProfileID attribute */
340 *q1_attr, /* ColorModel (or other) qualifier */
341 *q2_attr, /* MediaType (or other) qualifier */
342 *q3_attr; /* Resolution (or other) qualifier */
343 char q_keyword[PPD_MAX_NAME];
344 /* Qualifier keyword */
345 const char *q1_choice, /* ColorModel (or other) choice */
346 *q2_choice, /* MediaType (or other) choice */
347 *q3_choice; /* Resolution (or other) choice */
348 ppd_option_t *cm_option; /* Color model option */
349 ppd_choice_t *cm_choice; /* Color model choice */
350 int num_profiles; /* Number of profiles */
351 OSStatus error = 0; /* Last error */
352 unsigned device_id, /* Printer device ID */
353 profile_id = 0, /* Profile ID */
354 default_profile_id = 0;
355 /* Default profile ID */
356 CFMutableDictionaryRef device_name; /* Printer device name dictionary */
357 CFStringRef printer_name; /* Printer name string */
358 cups_array_t *languages; /* Languages array */
359 CFMutableDictionaryRef profiles, /* Dictionary of profiles */
360 profile; /* Current profile info dictionary */
361 CFStringRef dict_key; /* Key in factory profile dictionary */
362
363
364 /*
365 * Make sure ColorSync is available...
366 */
367
368 if (ColorSyncRegisterDevice == NULL)
369 return;
370
371 /*
372 * Try opening the PPD file for this printer...
373 */
374
375 snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
376 if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL)
377 return;
378
379 /*
380 * See if we have any profiles...
381 */
382
383 for (num_profiles = 0, attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
384 attr;
385 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
386 if (attr->spec[0] && attr->value && attr->value[0])
387 {
388 if (attr->value[0] != '/')
389 snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
390 attr->value);
391 else
392 strlcpy(iccfile, attr->value, sizeof(iccfile));
393
394 if (access(iccfile, 0))
395 {
396 cupsdLogMessage(CUPSD_LOG_ERROR,
397 "%s: ICC Profile \"%s\" does not exist.", p->name,
398 iccfile);
399 cupsdSetPrinterReasons(p, "+cups-missing-filter-warning");
400 continue;
401 }
402
403 num_profiles ++;
404 }
405
406 /*
407 * Create a dictionary for the factory profiles...
408 */
409
410 profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
411 &kCFTypeDictionaryKeyCallBacks,
412 &kCFTypeDictionaryValueCallBacks);
413 if (!profiles)
414 {
415 cupsdLogMessage(CUPSD_LOG_ERROR,
416 "Unable to allocate memory for factory profiles.");
417 ppdClose(ppd);
418 return;
419 }
420
421 /*
422 * If we have profiles, add them...
423 */
424
425 if (num_profiles > 0)
426 {
427 /*
428 * For CUPS PPDs, figure out the default profile selector values...
429 */
430
431 if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL &&
432 attr->value && attr->value[0])
433 {
434 snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
435 q1_attr = ppdFindAttr(ppd, q_keyword, NULL);
436 }
437 else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL)
438 q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
439
440 if (q1_attr && q1_attr->value && q1_attr->value[0])
441 q1_choice = q1_attr->value;
442 else
443 q1_choice = "";
444
445 if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
446 attr->value && attr->value[0])
447 {
448 snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
449 q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
450 }
451 else
452 q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
453
454 if (q2_attr && q2_attr->value && q2_attr->value[0])
455 q2_choice = q2_attr->value;
456 else
457 q2_choice = NULL;
458
459 if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
460 attr->value && attr->value[0])
461 {
462 snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
463 q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
464 }
465 else
466 q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
467
468 if (q3_attr && q3_attr->value && q3_attr->value[0])
469 q3_choice = q3_attr->value;
470 else
471 q3_choice = NULL;
472
473 /*
474 * Loop through the profiles listed in the PPD...
475 */
476
477 languages = _ppdGetLanguages(ppd);
478
479 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
480 attr;
481 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
482 if (attr->spec[0] && attr->value && attr->value[0])
483 {
484 /*
485 * Add this profile...
486 */
487
488 if (attr->value[0] != '/')
489 snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
490 attr->value);
491 else
492 strlcpy(iccfile, attr->value, sizeof(iccfile));
493
494 if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser,
495 cupsdLogFCMessage, p))
496 continue;
497
498 cupsArraySave(ppd->sorted_attrs);
499
500 if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID",
501 attr->spec)) != NULL &&
502 profileid_attr->value && isdigit(profileid_attr->value[0] & 255))
503 profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10);
504 else
505 profile_id = _ppdHashName(attr->spec);
506
507 cupsArrayRestore(ppd->sorted_attrs);
508
509 profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
510 &kCFTypeDictionaryKeyCallBacks,
511 &kCFTypeDictionaryValueCallBacks);
512 if (!profile)
513 {
514 cupsdLogMessage(CUPSD_LOG_ERROR,
515 "Unable to allocate memory for color profile.");
516 CFRelease(profiles);
517 ppdClose(ppd);
518 return;
519 }
520
521 apple_init_profile(ppd, languages, profile, profile_id, attr->spec,
522 attr->text[0] ? attr->text : attr->spec, iccfile);
523
524 dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
525 CFSTR("%u"), profile_id);
526 if (dict_key)
527 {
528 CFDictionarySetValue(profiles, dict_key, profile);
529 CFRelease(dict_key);
530 }
531
532 CFRelease(profile);
533
534 /*
535 * See if this is the default profile...
536 */
537
538 if (!default_profile_id && q1_choice && q2_choice && q3_choice)
539 {
540 snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice,
541 q3_choice);
542 if (!strcmp(selector, attr->spec))
543 default_profile_id = profile_id;
544 }
545
546 if (!default_profile_id && q1_choice && q2_choice)
547 {
548 snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice);
549 if (!strcmp(selector, attr->spec))
550 default_profile_id = profile_id;
551 }
552
553 if (!default_profile_id && q1_choice && q3_choice)
554 {
555 snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice);
556 if (!strcmp(selector, attr->spec))
557 default_profile_id = profile_id;
558 }
559
560 if (!default_profile_id && q1_choice)
561 {
562 snprintf(selector, sizeof(selector), "%s..", q1_choice);
563 if (!strcmp(selector, attr->spec))
564 default_profile_id = profile_id;
565 }
566
567 if (!default_profile_id && q2_choice && q3_choice)
568 {
569 snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice);
570 if (!strcmp(selector, attr->spec))
571 default_profile_id = profile_id;
572 }
573
574 if (!default_profile_id && q2_choice)
575 {
576 snprintf(selector, sizeof(selector), ".%s.", q2_choice);
577 if (!strcmp(selector, attr->spec))
578 default_profile_id = profile_id;
579 }
580
581 if (!default_profile_id && q3_choice)
582 {
583 snprintf(selector, sizeof(selector), "..%s", q3_choice);
584 if (!strcmp(selector, attr->spec))
585 default_profile_id = profile_id;
586 }
587 }
588
589 _ppdFreeLanguages(languages);
590 }
591 else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL)
592 {
593 /*
594 * Extract profiles from ColorModel option...
595 */
596
597 const char *profile_name; /* Name of generic profile */
598
599
600 num_profiles = cm_option->num_choices;
601
602 for (i = cm_option->num_choices, cm_choice = cm_option->choices;
603 i > 0;
604 i --, cm_choice ++)
605 {
606 if (!strcmp(cm_choice->choice, "Gray") ||
607 !strcmp(cm_choice->choice, "Black"))
608 profile_name = "Gray";
609 else if (!strcmp(cm_choice->choice, "RGB") ||
610 !strcmp(cm_choice->choice, "CMY"))
611 profile_name = "RGB";
612 else if (!strcmp(cm_choice->choice, "CMYK") ||
613 !strcmp(cm_choice->choice, "KCMY"))
614 profile_name = "CMYK";
615 else
616 profile_name = "DeviceN";
617
618 snprintf(selector, sizeof(selector), "%s..", profile_name);
619 profile_id = _ppdHashName(selector);
620
621 profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
622 &kCFTypeDictionaryKeyCallBacks,
623 &kCFTypeDictionaryValueCallBacks);
624 if (!profile)
625 {
626 cupsdLogMessage(CUPSD_LOG_ERROR,
627 "Unable to allocate memory for color profile.");
628 CFRelease(profiles);
629 ppdClose(ppd);
630 return;
631 }
632
633 apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice,
634 cm_choice->text, NULL);
635
636 dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
637 CFSTR("%u"), profile_id);
638 if (dict_key)
639 {
640 CFDictionarySetValue(profiles, dict_key, profile);
641 CFRelease(dict_key);
642 }
643
644 CFRelease(profile);
645
646 if (cm_choice->marked)
647 default_profile_id = profile_id;
648 }
649 }
650 else
651 {
652 /*
653 * Use the default colorspace...
654 */
655
656 attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
657
658 num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2;
659
660 /*
661 * Add the grayscale profile first. We always have a grayscale profile.
662 */
663
664 profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
665 &kCFTypeDictionaryKeyCallBacks,
666 &kCFTypeDictionaryValueCallBacks);
667
668 if (!profile)
669 {
670 cupsdLogMessage(CUPSD_LOG_ERROR,
671 "Unable to allocate memory for color profile.");
672 CFRelease(profiles);
673 ppdClose(ppd);
674 return;
675 }
676
677 profile_id = _ppdHashName("Gray..");
678 apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL);
679
680 dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
681 profile_id);
682 if (dict_key)
683 {
684 CFDictionarySetValue(profiles, dict_key, profile);
685 CFRelease(dict_key);
686 }
687
688 CFRelease(profile);
689
690 /*
691 * Then add the RGB/CMYK/DeviceN color profile...
692 */
693
694 profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
695 &kCFTypeDictionaryKeyCallBacks,
696 &kCFTypeDictionaryValueCallBacks);
697
698 if (!profile)
699 {
700 cupsdLogMessage(CUPSD_LOG_ERROR,
701 "Unable to allocate memory for color profile.");
702 CFRelease(profiles);
703 ppdClose(ppd);
704 return;
705 }
706
707 switch (ppd->colorspace)
708 {
709 default :
710 case PPD_CS_RGB :
711 case PPD_CS_CMY :
712 profile_id = _ppdHashName("RGB..");
713 apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB",
714 NULL);
715 break;
716
717 case PPD_CS_RGBK :
718 case PPD_CS_CMYK :
719 profile_id = _ppdHashName("CMYK..");
720 apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK",
721 NULL);
722 break;
723
724 case PPD_CS_GRAY :
725 if (attr)
726 break;
727
728 case PPD_CS_N :
729 profile_id = _ppdHashName("DeviceN..");
730 apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN",
731 "DeviceN", NULL);
732 break;
733 }
734
735 if (CFDictionaryGetCount(profile) > 0)
736 {
737 dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
738 CFSTR("%u"), profile_id);
739 if (dict_key)
740 {
741 CFDictionarySetValue(profiles, dict_key, profile);
742 CFRelease(dict_key);
743 }
744 }
745
746 CFRelease(profile);
747 }
748
749 if (num_profiles > 0)
750 {
751 /*
752 * Make sure we have a default profile ID...
753 */
754
755 if (!default_profile_id)
756 default_profile_id = profile_id; /* Last profile */
757
758 dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
759 default_profile_id);
760 if (dict_key)
761 {
762 CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID,
763 dict_key);
764 CFRelease(dict_key);
765 }
766
767 /*
768 * Get the device ID hash and pathelogical name dictionary.
769 */
770
771 cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"",
772 p->name);
773
774 device_id = _ppdHashName(p->name);
775 device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
776 &kCFTypeDictionaryKeyCallBacks,
777 &kCFTypeDictionaryValueCallBacks);
778 printer_name = CFStringCreateWithCString(kCFAllocatorDefault,
779 p->name, kCFStringEncodingUTF8);
780
781 if (device_name && printer_name)
782 {
783 /*
784 * Register the device with ColorSync...
785 */
786
787 CFTypeRef deviceDictKeys[] =
788 { /* Device keys */
789 kColorSyncDeviceDescriptions,
790 kColorSyncFactoryProfiles,
791 kColorSyncDeviceUserScope,
792 kColorSyncDeviceHostScope
793 };
794 CFTypeRef deviceDictVals[] =
795 { /* Device values */
796 device_name,
797 profiles,
798 kCFPreferencesAnyUser,
799 kCFPreferencesCurrentHost
800 };
801 CFDictionaryRef deviceDict; /* Device dictionary */
802 CFUUIDRef deviceUUID; /* Device UUID */
803
804 CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name);
805
806 deviceDict = CFDictionaryCreate(kCFAllocatorDefault,
807 (const void **)deviceDictKeys,
808 (const void **)deviceDictVals,
809 sizeof(deviceDictKeys) /
810 sizeof(deviceDictKeys[0]),
811 &kCFTypeDictionaryKeyCallBacks,
812 &kCFTypeDictionaryValueCallBacks);
813 deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id);
814
815 if (!deviceDict || !deviceUUID ||
816 !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID,
817 deviceDict))
818 error = 1001;
819
820 if (deviceUUID)
821 CFRelease(deviceUUID);
822
823 if (deviceDict)
824 CFRelease(deviceDict);
825 }
826 else
827 error = 1000;
828
829 /*
830 * Clean up...
831 */
832
833 if (error != noErr)
834 cupsdLogMessage(CUPSD_LOG_ERROR,
835 "Unable to register ICC color profiles for \"%s\": %d",
836 p->name, (int)error);
837
838 if (printer_name)
839 CFRelease(printer_name);
840
841 if (device_name)
842 CFRelease(device_name);
843 }
844
845 /*
846 * Free any memory we used...
847 */
848
849 CFRelease(profiles);
850
851 ppdClose(ppd);
852 }
853
854
855 /*
856 * 'apple_unregister_profiles()' - Remove color profiles for the specified
857 * printer.
858 */
859
860 static void
861 apple_unregister_profiles(
862 cupsd_printer_t *p) /* I - Printer */
863 {
864 /*
865 * Make sure ColorSync is available...
866 */
867
868 if (ColorSyncUnregisterDevice != NULL)
869 {
870 CFUUIDRef deviceUUID; /* Device UUID */
871
872 deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name));
873 if (deviceUUID)
874 {
875 ColorSyncUnregisterDevice(kColorSyncPrinterDeviceClass, deviceUUID);
876 CFRelease(deviceUUID);
877 }
878 }
879 }
880
881
882 #elif defined(HAVE_DBUS)
883 /*
884 * 'colord_create_device()' - Create a device and register profiles.
885 */
886
887 static void
888 colord_create_device(
889 cupsd_printer_t *p, /* I - Printer */
890 ppd_file_t *ppd, /* I - PPD file */
891 cups_array_t *profiles, /* I - Profiles array */
892 const char *colorspace, /* I - Device colorspace, e.g. 'rgb' */
893 char **format, /* I - Device qualifier format */
894 const char *relation, /* I - Profile relation, either 'soft'
895 or 'hard' */
896 const char *scope) /* I - The scope of the device, e.g.
897 'normal', 'temp' or 'disk' */
898 {
899 DBusMessage *message = NULL; /* D-Bus request */
900 DBusMessage *reply = NULL; /* D-Bus reply */
901 DBusMessageIter args; /* D-Bus method arguments */
902 DBusMessageIter dict; /* D-Bus method arguments */
903 DBusError error; /* D-Bus error */
904 const char *device_path; /* Device object path */
905 const char *profile_path; /* Profile path */
906 char *default_profile_path = NULL;
907 /* Default profile path */
908 char device_id[1024]; /* Device ID as understood by colord */
909 char format_str[1024]; /* Qualifier format as a string */
910
911
912 /*
913 * Create the device...
914 */
915
916 snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
917 device_path = device_id;
918
919 message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "CreateDevice");
920
921 dbus_message_iter_init_append(message, &args);
922 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
923 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
924
925 snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1],
926 format[2]);
927
928 dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict);
929 colord_dict_add_strings(&dict, "Colorspace", colorspace);
930 colord_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
931 if (ppd->manufacturer)
932 colord_dict_add_strings(&dict, "Vendor", ppd->manufacturer);
933 if (ppd->modelname)
934 colord_dict_add_strings(&dict, "Model", ppd->modelname);
935 if (p->sanitized_device_uri)
936 colord_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
937 colord_dict_add_strings(&dict, "Format", format_str);
938 colord_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
939 dbus_message_iter_close_container(&args, &dict);
940
941 /*
942 * Send the CreateDevice request synchronously...
943 */
944
945 dbus_error_init(&error);
946 cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)", device_id,
947 scope);
948 reply = dbus_connection_send_with_reply_and_block(colord_con, message,
949 COLORD_DBUS_TIMEOUT,
950 &error);
951 if (!reply)
952 {
953 cupsdLogMessage(CUPSD_LOG_WARN, "CreateDevice failed: %s:%s", error.name,
954 error.message);
955 dbus_error_free(&error);
956 goto out;
957 }
958
959 /*
960 * Get reply data...
961 */
962
963 dbus_message_iter_init(reply, &args);
964 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
965 {
966 cupsdLogMessage(CUPSD_LOG_WARN,
967 "CreateDevice failed: Incorrect reply type.");
968 goto out;
969 }
970
971 dbus_message_iter_get_basic(&args, &device_path);
972 cupsdLogMessage(CUPSD_LOG_DEBUG, "Created device \"%s\".", device_path);
973
974 /*
975 * Add profiles...
976 */
977
978 for (profile_path = cupsArrayFirst(profiles);
979 profile_path;
980 profile_path = cupsArrayNext(profiles))
981 {
982 colord_device_add_profile(device_path, profile_path, relation);
983 }
984
985 out:
986
987 if (default_profile_path)
988 free(default_profile_path);
989
990 if (message)
991 dbus_message_unref(message);
992
993 if (reply)
994 dbus_message_unref(reply);
995 }
996
997
998 /*
999 * 'colord_create_profile()' - Create a color profile for a printer.
1000 */
1001
1002 static void
1003 colord_create_profile(
1004 cups_array_t *profiles, /* I - Profiles array */
1005 const char *printer_name, /* I - Printer name */
1006 const char *qualifier, /* I - Profile qualifier */
1007 const char *colorspace, /* I - Profile colorspace */
1008 char **format, /* I - Profile qualifier format */
1009 const char *iccfile, /* I - ICC filename */
1010 const char *scope) /* I - The scope of the profile, e.g.
1011 'normal', 'temp' or 'disk' */
1012 {
1013 DBusMessage *message = NULL; /* D-Bus request */
1014 DBusMessage *reply = NULL; /* D-Bus reply */
1015 DBusMessageIter args; /* D-Bus method arguments */
1016 DBusMessageIter dict; /* D-Bus method arguments */
1017 DBusError error; /* D-Bus error */
1018 char *idstr; /* Profile ID string */
1019 size_t idstrlen; /* Profile ID allocated length */
1020 const char *profile_path; /* Device object path */
1021 char format_str[1024]; /* Qualifier format as a string */
1022
1023
1024 /*
1025 * Create the profile...
1026 */
1027
1028 message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "CreateProfile");
1029
1030 idstrlen = strlen(printer_name) + 1 + strlen(qualifier) + 1;
1031 if ((idstr = malloc(idstrlen)) == NULL)
1032 goto out;
1033 snprintf(idstr, idstrlen, "%s-%s", printer_name, qualifier);
1034 cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile ID \"%s\".", idstr);
1035
1036 dbus_message_iter_init_append(message, &args);
1037 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
1038 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
1039
1040 snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1],
1041 format[2]);
1042
1043 dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict);
1044 colord_dict_add_strings(&dict, "Qualifier", qualifier);
1045 colord_dict_add_strings(&dict, "Format", format_str);
1046 colord_dict_add_strings(&dict, "Colorspace", colorspace);
1047 if (iccfile)
1048 colord_dict_add_strings(&dict, "Filename", iccfile);
1049 dbus_message_iter_close_container(&args, &dict);
1050
1051 /*
1052 * Send the CreateProfile request synchronously...
1053 */
1054
1055 dbus_error_init(&error);
1056 cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)", idstr,
1057 scope);
1058 reply = dbus_connection_send_with_reply_and_block(colord_con, message,
1059 COLORD_DBUS_TIMEOUT,
1060 &error);
1061 if (!reply)
1062 {
1063 cupsdLogMessage(CUPSD_LOG_WARN, "CreateProfile failed: %s:%s", error.name,
1064 error.message);
1065 dbus_error_free(&error);
1066 goto out;
1067 }
1068
1069 /*
1070 * Get reply data...
1071 */
1072
1073 dbus_message_iter_init(reply, &args);
1074 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
1075 {
1076 cupsdLogMessage(CUPSD_LOG_WARN,
1077 "CreateProfile failed: Incorrect reply type.");
1078 goto out;
1079 }
1080
1081 dbus_message_iter_get_basic(&args, &profile_path);
1082 cupsdLogMessage(CUPSD_LOG_DEBUG, "Created profile \"%s\".", profile_path);
1083 cupsArrayAdd(profiles, strdup(profile_path));
1084
1085 out:
1086
1087 if (message)
1088 dbus_message_unref(message);
1089
1090 if (reply)
1091 dbus_message_unref(reply);
1092
1093 if (idstr)
1094 free(idstr);
1095 }
1096
1097
1098 /*
1099 * 'colord_delete_device()' - Delete a device
1100 */
1101
1102 static void
1103 colord_delete_device(
1104 const char *device_id) /* I - Device ID string */
1105 {
1106 DBusMessage *message = NULL; /* D-Bus request */
1107 DBusMessage *reply = NULL; /* D-Bus reply */
1108 DBusMessageIter args; /* D-Bus method arguments */
1109 DBusError error; /* D-Bus error */
1110 char *device_path; /* Device object path */
1111
1112
1113 /*
1114 * Find the device...
1115 */
1116
1117 if ((device_path = colord_find_device(device_id)) == NULL)
1118 goto out;
1119
1120 /*
1121 * Delete the device...
1122 */
1123
1124 message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "DeleteDevice");
1125
1126 dbus_message_iter_init_append(message, &args);
1127 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
1128
1129 /*
1130 * Send the DeleteDevice request synchronously...
1131 */
1132
1133 dbus_error_init(&error);
1134 cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
1135 reply = dbus_connection_send_with_reply_and_block(colord_con, message,
1136 COLORD_DBUS_TIMEOUT,
1137 &error);
1138 if (!reply)
1139 {
1140 cupsdLogMessage(CUPSD_LOG_DEBUG, "DeleteDevice failed: %s:%s", error.name,
1141 error.message);
1142 dbus_error_free(&error);
1143 goto out;
1144 }
1145
1146 out:
1147
1148 if (device_path)
1149 free(device_path);
1150
1151 if (message)
1152 dbus_message_unref(message);
1153
1154 if (reply)
1155 dbus_message_unref(reply);
1156 }
1157
1158
1159 /*
1160 * 'colord_device_add_profile()' - Assign a profile to a device.
1161 */
1162
1163 static void
1164 colord_device_add_profile(
1165 const char *device_path, /* I - Device object path */
1166 const char *profile_path, /* I - Profile object path */
1167 const char *relation) /* I - Device relation, either
1168 'soft' or 'hard' */
1169 {
1170 DBusMessage *message = NULL; /* D-Bus request */
1171 DBusMessage *reply = NULL; /* D-Bus reply */
1172 DBusMessageIter args; /* D-Bus method arguments */
1173 DBusError error; /* D-Bus error */
1174
1175
1176 message = COLORD_DBUS_MSG(device_path, "AddProfile");
1177
1178 dbus_message_iter_init_append(message, &args);
1179 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
1180 dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
1181 cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling %s:AddProfile(%s) [%s]",
1182 device_path, profile_path, relation);
1183
1184 /*
1185 * Send the AddProfile request synchronously...
1186 */
1187
1188 dbus_error_init(&error);
1189 reply = dbus_connection_send_with_reply_and_block(colord_con, message,
1190 COLORD_DBUS_TIMEOUT,
1191 &error);
1192 if (!reply)
1193 {
1194 cupsdLogMessage(CUPSD_LOG_WARN, "AddProfile failed: %s:%s", error.name,
1195 error.message);
1196 dbus_error_free(&error);
1197 goto out;
1198 }
1199
1200 out:
1201
1202 if (message)
1203 dbus_message_unref(message);
1204
1205 if (reply)
1206 dbus_message_unref(reply);
1207 }
1208
1209
1210 /*
1211 * 'colord_dict_add_strings()' - Add two strings to a dictionary.
1212 */
1213
1214 static void
1215 colord_dict_add_strings(
1216 DBusMessageIter *dict, /* I - Dictionary */
1217 const char *key, /* I - Key string */
1218 const char *value) /* I - Value string */
1219 {
1220 DBusMessageIter entry; /* Entry to add */
1221
1222
1223 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
1224 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1225 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
1226 dbus_message_iter_close_container(dict, &entry);
1227 }
1228
1229
1230 /*
1231 * 'colord_find_device()' - Finds a device
1232 */
1233
1234 static char * /* O - Device path or NULL */
1235 colord_find_device(
1236 const char *device_id) /* I - Device ID string */
1237 {
1238 DBusMessage *message = NULL; /* D-Bus request */
1239 DBusMessage *reply = NULL; /* D-Bus reply */
1240 DBusMessageIter args; /* D-Bus method arguments */
1241 DBusError error; /* D-Bus error */
1242 const char *device_path_tmp; /* Device object path */
1243 char *device_path = NULL; /* Device object path */
1244
1245
1246 message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "FindDeviceById");
1247
1248 dbus_message_iter_init_append(message, &args);
1249 dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
1250
1251 /*
1252 * Send the FindDeviceById request synchronously...
1253 */
1254
1255 dbus_error_init(&error);
1256 cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById(%s)", device_id);
1257 reply = dbus_connection_send_with_reply_and_block(colord_con, message,
1258 COLORD_DBUS_TIMEOUT,
1259 &error);
1260 if (!reply)
1261 {
1262 cupsdLogMessage(CUPSD_LOG_DEBUG, "FindDeviceById failed: %s:%s",
1263 error.name, error.message);
1264 dbus_error_free(&error);
1265 goto out;
1266 }
1267
1268 /*
1269 * Get reply data...
1270 */
1271
1272 dbus_message_iter_init(reply, &args);
1273 if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
1274 {
1275 cupsdLogMessage(CUPSD_LOG_WARN,
1276 "FindDeviceById failed: Incorrect reply type.");
1277 goto out;
1278 }
1279
1280 dbus_message_iter_get_basic(&args, &device_path_tmp);
1281 if (device_path_tmp)
1282 device_path = strdup(device_path_tmp);
1283
1284 out:
1285
1286 if (message)
1287 dbus_message_unref(message);
1288
1289 if (reply)
1290 dbus_message_unref(reply);
1291
1292 return (device_path);
1293 }
1294
1295
1296 /*
1297 * 'colord_get_qualifier_format()' - Get the qualifier format.
1298 *
1299 * Note: Returns a value of "ColorSpace.MediaType.Resolution" by default.
1300 */
1301
1302 static void
1303 colord_get_qualifier_format(
1304 ppd_file_t *ppd, /* I - PPD file data */
1305 char *format[3]) /* I - Format tuple */
1306 {
1307 const char *tmp; /* Temporary string */
1308 ppd_attr_t *attr; /* Profile attributes */
1309
1310
1311 /*
1312 * Get 1st section...
1313 */
1314
1315 if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL)
1316 tmp = attr->value;
1317 else if (ppdFindAttr(ppd, "DefaultColorModel", NULL))
1318 tmp = "ColorModel";
1319 else if (ppdFindAttr(ppd, "DefaultColorSpace", NULL))
1320 tmp = "ColorSpace";
1321 else
1322 tmp = "";
1323
1324 format[0] = strdup(tmp);
1325
1326 /*
1327 * Get 2nd section...
1328 */
1329
1330 if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL)
1331 tmp = attr->value;
1332 else
1333 tmp = "MediaType";
1334
1335 format[1] = strdup(tmp);
1336
1337 /*
1338 * Get 3rd section...
1339 */
1340
1341 if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL)
1342 tmp = attr->value;
1343 else
1344 tmp = "Resolution";
1345
1346 format[2] = strdup(tmp);
1347 }
1348
1349
1350 /*
1351 * 'colord_register_printer()' - Register profiles for a printer.
1352 */
1353
1354 static void
1355 colord_register_printer(
1356 cupsd_printer_t *p) /* I - printer */
1357 {
1358 char ppdfile[1024], /* PPD filename */
1359 iccfile[1024]; /* ICC filename */
1360 ppd_file_t *ppd; /* PPD file */
1361 cups_array_t *profiles; /* Profile paths array */
1362 ppd_attr_t *attr; /* Profile attributes */
1363 const char *device_colorspace; /* Device colorspace */
1364 char *format[3]; /* Qualifier format tuple */
1365
1366
1367 /*
1368 * Ensure we have a D-Bus connection...
1369 */
1370
1371 if (!colord_con)
1372 return;
1373
1374 /*
1375 * Try opening the PPD file for this printer...
1376 */
1377
1378 snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
1379 if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL)
1380 return;
1381
1382 /*
1383 * Find out the qualifier format
1384 */
1385
1386 colord_get_qualifier_format(ppd, format);
1387
1388 /*
1389 * See if we have any embedded profiles...
1390 */
1391
1392 profiles = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup,
1393 (cups_afree_func_t)free);
1394 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
1395 attr;
1396 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
1397 if (attr->spec[0] && attr->value && attr->value[0])
1398 {
1399 if (attr->value[0] != '/')
1400 snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
1401 attr->value);
1402 else
1403 strlcpy(iccfile, attr->value, sizeof(iccfile));
1404
1405 if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser,
1406 cupsdLogFCMessage, p))
1407 continue;
1408
1409 colord_create_profile(profiles, p->name, attr->spec, COLORD_SPACE_UNKNOWN,
1410 format, iccfile, COLORD_SCOPE_TEMP);
1411 }
1412
1413 /*
1414 * Add the grayscale profile first. We always have a grayscale profile.
1415 */
1416
1417 colord_create_profile(profiles, p->name, "Gray..", COLORD_SPACE_GRAY,
1418 format, NULL, COLORD_SCOPE_TEMP);
1419
1420 /*
1421 * Then add the RGB/CMYK/DeviceN color profile...
1422 */
1423
1424 device_colorspace = "unknown";
1425 switch (ppd->colorspace)
1426 {
1427 case PPD_CS_RGB :
1428 case PPD_CS_CMY :
1429 device_colorspace = COLORD_SPACE_RGB;
1430 colord_create_profile(profiles, p->name, "RGB..", COLORD_SPACE_RGB,
1431 format, NULL, COLORD_SCOPE_TEMP);
1432 break;
1433
1434 case PPD_CS_RGBK :
1435 case PPD_CS_CMYK :
1436 device_colorspace = COLORD_SPACE_CMYK;
1437 colord_create_profile(profiles, p->name, "CMYK..", COLORD_SPACE_CMYK,
1438 format, NULL, COLORD_SCOPE_TEMP);
1439 break;
1440
1441 case PPD_CS_GRAY :
1442 device_colorspace = COLORD_SPACE_GRAY;
1443 break;
1444
1445 case PPD_CS_N :
1446 colord_create_profile(profiles, p->name, "DeviceN..",
1447 COLORD_SPACE_UNKNOWN, format, NULL,
1448 COLORD_SCOPE_TEMP);
1449 break;
1450 }
1451
1452 /*
1453 * Register the device with colord.
1454 */
1455
1456 cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\".",
1457 p->name);
1458 colord_create_device(p, ppd, profiles, device_colorspace, format,
1459 COLORD_RELATION_SOFT, COLORD_SCOPE_TEMP);
1460
1461 /*
1462 * Free any memory we used...
1463 */
1464
1465 cupsArrayDelete(profiles);
1466
1467 free(format[0]);
1468 free(format[1]);
1469 free(format[2]);
1470
1471 ppdClose(ppd);
1472 }
1473
1474
1475 /*
1476 * 'colord_unregister_printer()' - Unregister profiles for a printer.
1477 */
1478
1479 static void
1480 colord_unregister_printer(
1481 cupsd_printer_t *p) /* I - printer */
1482 {
1483 char device_id[1024]; /* Device ID as understood by colord */
1484
1485
1486 /*
1487 * Ensure we have a D-Bus connection...
1488 */
1489
1490 if (!colord_con)
1491 return;
1492
1493 /*
1494 * Just delete the device itself, and leave the profiles registered
1495 */
1496
1497 snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
1498 colord_delete_device(device_id);
1499 }
1500 #endif /* __APPLE__ */
1501
1502
1503 /*
1504 * End of "$Id$".
1505 */