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