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