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