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