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