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