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