2 * "$Id: dest.c 9568 2011-02-25 06:13:56Z mike $"
4 * User-defined destination (and option) support for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * cupsAddDest() - Add a destination to the list of
21 * _cupsAppleCopyDefaultPaperID() - Get the default paper ID.
22 * _cupsAppleCopyDefaultPrinter() - Get the default printer at this location.
23 * _cupsAppleGetUseLastPrinter() - Get whether to use the last used printer.
24 * _cupsAppleSetDefaultPaperID() - Set the default paper id.
25 * _cupsAppleSetDefaultPrinter() - Set the default printer for this location.
26 * _cupsAppleSetUseLastPrinter() - Set whether to use the last used printer.
27 * cupsFreeDests() - Free the memory used by the list of
29 * cupsGetDest() - Get the named destination from the list.
30 * _cupsGetDests() - Get destinations from a server.
31 * cupsGetDests() - Get the list of destinations from the
33 * cupsGetDests2() - Get the list of destinations from the
35 * cupsGetNamedDest() - Get options for the named destination.
36 * cupsRemoveDest() - Remove a destination from the destination
38 * cupsSetDefaultDest() - Set the default destination.
39 * cupsSetDests() - Save the list of destinations for the
41 * cupsSetDests2() - Save the list of destinations for the
43 * _cupsUserDefault() - Get the user default printer from
44 * environment variables and location
46 * appleCopyLocations() - Copy the location history array.
47 * appleCopyNetwork() - Get the network ID for the current
49 * appleGetPaperSize() - Get the default paper size.
50 * appleGetPrinter() - Get a printer from the history array.
51 * cups_add_dest() - Add a destination to the array.
52 * cups_compare_dests() - Compare two destinations.
53 * cups_find_dest() - Find a destination using a binary search.
54 * cups_get_default() - Get the default destination from an
56 * cups_get_dests() - Get destinations from a file.
57 * cups_make_string() - Make a comma-separated string of values
58 * from an IPP attribute.
62 * Include necessary headers...
65 #include "cups-private.h"
70 #endif /* HAVE_NOTIFY_H */
73 # include <SystemConfiguration/SystemConfiguration.h>
74 # define kCUPSPrintingPrefs CFSTR("org.cups.PrintingPrefs")
75 # define kDefaultPaperIDKey CFSTR("DefaultPaperID")
76 # define kLastUsedPrintersKey CFSTR("LastUsedPrinters")
77 # define kLocationNetworkKey CFSTR("Network")
78 # define kLocationPrinterIDKey CFSTR("PrinterID")
79 # define kUseLastPrinter CFSTR("UseLastPrinter")
80 #endif /* __APPLE__ */
88 static CFArrayRef
appleCopyLocations(void);
89 static CFStringRef
appleCopyNetwork(void);
90 static char *appleGetPaperSize(char *name
, int namesize
);
91 static CFStringRef
appleGetPrinter(CFArrayRef locations
, CFStringRef network
,
93 #endif /* __APPLE__ */
94 static cups_dest_t
*cups_add_dest(const char *name
, const char *instance
,
95 int *num_dests
, cups_dest_t
**dests
);
96 static int cups_compare_dests(cups_dest_t
*a
, cups_dest_t
*b
);
97 static int cups_find_dest(const char *name
, const char *instance
,
98 int num_dests
, cups_dest_t
*dests
, int prev
,
100 static char *cups_get_default(const char *filename
, char *namebuf
,
101 size_t namesize
, const char **instance
);
102 static int cups_get_dests(const char *filename
, const char *match_name
,
103 const char *match_inst
, int user_default_set
,
104 int num_dests
, cups_dest_t
**dests
);
105 static char *cups_make_string(ipp_attribute_t
*attr
, char *buffer
,
110 * 'cupsAddDest()' - Add a destination to the list of destinations.
112 * This function cannot be used to add a new class or printer queue,
113 * it only adds a new container of saved options for the named
114 * destination or instance.
116 * If the named destination already exists, the destination list is
117 * returned unchanged. Adding a new instance of a destination creates
118 * a copy of that destination's options.
120 * Use the @link cupsSaveDests@ function to save the updated list of
121 * destinations to the user's lpoptions file.
124 int /* O - New number of destinations */
125 cupsAddDest(const char *name
, /* I - Destination name */
126 const char *instance
, /* I - Instance name or @code NULL@ for none/primary */
127 int num_dests
, /* I - Number of destinations */
128 cups_dest_t
**dests
) /* IO - Destinations */
130 int i
; /* Looping var */
131 cups_dest_t
*dest
; /* Destination pointer */
132 cups_dest_t
*parent
= NULL
; /* Parent destination */
133 cups_option_t
*doption
, /* Current destination option */
134 *poption
; /* Current parent option */
140 if (!cupsGetDest(name
, instance
, num_dests
, *dests
))
142 if (instance
&& !cupsGetDest(name
, NULL
, num_dests
, *dests
))
145 dest
= cups_add_dest(name
, instance
, &num_dests
, dests
);
148 * Find the base dest again now the array has been realloc'd.
151 parent
= cupsGetDest(name
, NULL
, num_dests
, *dests
);
153 if (instance
&& parent
&& parent
->num_options
> 0)
156 * Copy options from parent...
159 dest
->options
= calloc(sizeof(cups_option_t
), parent
->num_options
);
163 dest
->num_options
= parent
->num_options
;
165 for (i
= dest
->num_options
, doption
= dest
->options
,
166 poption
= parent
->options
;
168 i
--, doption
++, poption
++)
170 doption
->name
= _cupsStrRetain(poption
->name
);
171 doption
->value
= _cupsStrRetain(poption
->value
);
183 * '_cupsAppleCopyDefaultPaperID()' - Get the default paper ID.
186 CFStringRef
/* O - Default paper ID */
187 _cupsAppleCopyDefaultPaperID(void)
189 return (CFPreferencesCopyAppValue(kDefaultPaperIDKey
,
190 kCUPSPrintingPrefs
));
195 * '_cupsAppleCopyDefaultPrinter()' - Get the default printer at this location.
198 CFStringRef
/* O - Default printer name */
199 _cupsAppleCopyDefaultPrinter(void)
201 CFStringRef network
; /* Network location */
202 CFArrayRef locations
; /* Location array */
203 CFStringRef locprinter
; /* Current printer */
207 * Use location-based defaults only if "use last printer" is selected in the
208 * system preferences...
211 if (!_cupsAppleGetUseLastPrinter())
213 DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Not using last printer as "
219 * Get the current location...
222 if ((network
= appleCopyNetwork()) == NULL
)
224 DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Unable to get current "
230 // CFStringGetCString(network, name, namesize, kCFStringEncodingUTF8);
231 // DEBUG_printf(("2_cupsUserDefault: network=\"%s\"", name));
232 //# endif /* DEBUG */
235 * Lookup the network in the preferences...
238 if ((locations
= appleCopyLocations()) == NULL
)
241 * Missing or bad location array, so no location-based default...
244 DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Missing or bad last used "
252 DEBUG_printf(("1_cupsAppleCopyDefaultPrinter: Got locations, %d entries.",
253 (int)CFArrayGetCount(locations
)));
255 if ((locprinter
= appleGetPrinter(locations
, network
, NULL
)) != NULL
)
256 CFRetain(locprinter
);
259 CFRelease(locations
);
266 * '_cupsAppleGetUseLastPrinter()' - Get whether to use the last used printer.
269 int /* O - 1 to use last printer, 0 otherwise */
270 _cupsAppleGetUseLastPrinter(void)
272 Boolean uselast
, /* Use last printer preference value */
273 uselast_set
; /* Valid is set? */
276 if (getenv("CUPS_DISABLE_APPLE_DEFAULT"))
279 uselast
= CFPreferencesGetAppBooleanValue(kUseLastPrinter
,
290 * '_cupsAppleSetDefaultPaperID()' - Set the default paper id.
294 _cupsAppleSetDefaultPaperID(
295 CFStringRef name
) /* I - New paper ID */
297 CFPreferencesSetAppValue(kDefaultPaperIDKey
, name
, kCUPSPrintingPrefs
);
298 CFPreferencesAppSynchronize(kCUPSPrintingPrefs
);
299 notify_post("com.apple.printerPrefsChange");
304 * '_cupsAppleSetDefaultPrinter()' - Set the default printer for this location.
308 _cupsAppleSetDefaultPrinter(
309 CFStringRef name
) /* I - Default printer/class name */
311 CFStringRef network
; /* Current network */
312 CFArrayRef locations
; /* Old locations array */
313 CFIndex locindex
; /* Index in locations array */
314 CFStringRef locprinter
; /* Current printer */
315 CFMutableArrayRef newlocations
; /* New locations array */
316 CFMutableDictionaryRef newlocation
; /* New location */
320 * Get the current location...
323 if ((network
= appleCopyNetwork()) == NULL
)
325 DEBUG_puts("1_cupsAppleSetDefaultPrinter: Unable to get current network...");
330 * Lookup the network in the preferences...
333 if ((locations
= appleCopyLocations()) != NULL
)
334 locprinter
= appleGetPrinter(locations
, network
, &locindex
);
341 if (!locprinter
|| CFStringCompare(locprinter
, name
, 0) != kCFCompareEqualTo
)
344 * Need to change the locations array...
349 newlocations
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0,
353 CFArrayRemoveValueAtIndex(newlocations
, locindex
);
356 newlocations
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
357 &kCFTypeArrayCallBacks
);
359 newlocation
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
360 &kCFTypeDictionaryKeyCallBacks
,
361 &kCFTypeDictionaryValueCallBacks
);
363 if (newlocation
&& newlocations
)
366 * Put the new location at the front of the array...
369 CFDictionaryAddValue(newlocation
, kLocationNetworkKey
, network
);
370 CFDictionaryAddValue(newlocation
, kLocationPrinterIDKey
, name
);
371 CFArrayInsertValueAtIndex(newlocations
, 0, newlocation
);
374 * Limit the number of locations to 10...
377 while (CFArrayGetCount(newlocations
) > 10)
378 CFArrayRemoveValueAtIndex(newlocations
, 10);
381 * Push the changes out...
384 CFPreferencesSetAppValue(kLastUsedPrintersKey
, newlocations
,
386 CFPreferencesAppSynchronize(kCUPSPrintingPrefs
);
387 notify_post("com.apple.printerPrefsChange");
391 CFRelease(newlocations
);
394 CFRelease(newlocation
);
398 CFRelease(locations
);
405 * '_cupsAppleSetUseLastPrinter()' - Set whether to use the last used printer.
409 _cupsAppleSetUseLastPrinter(
410 int uselast
) /* O - 1 to use last printer, 0 otherwise */
412 CFPreferencesSetAppValue(kUseLastPrinter
,
413 uselast
? kCFBooleanTrue
: kCFBooleanFalse
,
415 CFPreferencesAppSynchronize(kCUPSPrintingPrefs
);
416 notify_post("com.apple.printerPrefsChange");
418 #endif /* __APPLE__ */
422 * 'cupsFreeDests()' - Free the memory used by the list of destinations.
426 cupsFreeDests(int num_dests
, /* I - Number of destinations */
427 cups_dest_t
*dests
) /* I - Destinations */
429 int i
; /* Looping var */
430 cups_dest_t
*dest
; /* Current destination */
433 if (num_dests
== 0 || dests
== NULL
)
436 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
438 _cupsStrFree(dest
->name
);
439 _cupsStrFree(dest
->instance
);
441 cupsFreeOptions(dest
->num_options
, dest
->options
);
449 * 'cupsGetDest()' - Get the named destination from the list.
451 * Use the @link cupsGetDests@ or @link cupsGetDests2@ functions to get a
452 * list of supported destinations for the current user.
455 cups_dest_t
* /* O - Destination pointer or @code NULL@ */
456 cupsGetDest(const char *name
, /* I - Destination name or @code NULL@ for the default destination */
457 const char *instance
, /* I - Instance name or @code NULL@ */
458 int num_dests
, /* I - Number of destinations */
459 cups_dest_t
*dests
) /* I - Destinations */
461 int diff
, /* Result of comparison */
462 match
; /* Matching index */
465 if (num_dests
<= 0 || !dests
)
471 * NULL name for default printer.
474 while (num_dests
> 0)
476 if (dests
->is_default
)
486 * Lookup name and optionally the instance...
489 match
= cups_find_dest(name
, instance
, num_dests
, dests
, -1, &diff
);
492 return (dests
+ match
);
500 * '_cupsGetDests()' - Get destinations from a server.
502 * "op" is CUPS_GET_PRINTERS to get a full list, CUPS_GET_DEFAULT to get the
503 * system-wide default printer, or IPP_GET_PRINTER_ATTRIBUTES for a known
506 * "name" is the name of an existing printer and is only used when "op" is
507 * IPP_GET_PRINTER_ATTRIBUTES.
509 * "dest" is initialized to point to the array of destinations.
511 * 0 is returned if there are no printers, no default printer, or the named
512 * printer does not exist, respectively.
514 * Free the memory used by the destination array using the @link cupsFreeDests@
517 * Note: On Mac OS X this function also gets the default paper from the system
518 * preferences (~/L/P/org.cups.PrintingPrefs.plist) and includes it in the
519 * options array for each destination that supports it.
522 int /* O - Number of destinations */
523 _cupsGetDests(http_t
*http
, /* I - Connection to server or CUPS_HTTP_DEFAULT */
524 ipp_op_t op
, /* I - IPP operation */
525 const char *name
, /* I - Name of destination */
526 cups_dest_t
**dests
) /* IO - Destinations */
528 int num_dests
= 0; /* Number of destinations */
529 cups_dest_t
*dest
; /* Current destination */
530 ipp_t
*request
, /* IPP Request */
531 *response
; /* IPP Response */
532 ipp_attribute_t
*attr
; /* Current attribute */
533 const char *printer_name
; /* printer-name attribute */
534 char uri
[1024]; /* printer-uri value */
535 int num_options
; /* Number of options */
536 cups_option_t
*options
; /* Options */
538 char media_default
[41]; /* Default paper size */
539 #endif /* __APPLE__ */
540 char optname
[1024], /* Option name */
541 value
[2048], /* Option value */
542 *ptr
; /* Pointer into name/value */
543 static const char * const pattrs
[] = /* Attributes we're interested in */
545 "auth-info-required",
547 "job-sheets-default",
548 "marker-change-time",
550 "marker-high-levels",
558 #endif /* __APPLE__ */
562 "printer-is-accepting-jobs",
565 "printer-make-and-model",
568 "printer-state-change-time",
569 "printer-state-reasons",
571 "printer-uri-supported"
577 * Get the default paper size...
580 appleGetPaperSize(media_default
, sizeof(media_default
));
581 #endif /* __APPLE__ */
584 * Build a CUPS_GET_PRINTERS or IPP_GET_PRINTER_ATTRIBUTES request, which
585 * require the following attributes:
588 * attributes-natural-language
589 * requesting-user-name
590 * printer-uri [for IPP_GET_PRINTER_ATTRIBUTES]
593 request
= ippNewRequest(op
);
595 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
596 "requested-attributes", sizeof(pattrs
) / sizeof(pattrs
[0]),
599 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
600 "requesting-user-name", NULL
, cupsUser());
602 if (name
&& op
!= CUPS_GET_DEFAULT
)
604 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
605 "localhost", ippPort(), "/printers/%s", name
);
606 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
611 * Do the request and get back a response...
614 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
616 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
619 * Skip leading attributes until we hit a printer...
622 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
629 * Pull the needed attributes from this printer...
636 for (; attr
&& attr
->group_tag
== IPP_TAG_PRINTER
; attr
= attr
->next
)
638 if (attr
->value_tag
!= IPP_TAG_INTEGER
&&
639 attr
->value_tag
!= IPP_TAG_ENUM
&&
640 attr
->value_tag
!= IPP_TAG_BOOLEAN
&&
641 attr
->value_tag
!= IPP_TAG_TEXT
&&
642 attr
->value_tag
!= IPP_TAG_TEXTLANG
&&
643 attr
->value_tag
!= IPP_TAG_NAME
&&
644 attr
->value_tag
!= IPP_TAG_NAMELANG
&&
645 attr
->value_tag
!= IPP_TAG_KEYWORD
&&
646 attr
->value_tag
!= IPP_TAG_RANGE
&&
647 attr
->value_tag
!= IPP_TAG_URI
)
650 if (!strcmp(attr
->name
, "auth-info-required") ||
651 !strcmp(attr
->name
, "device-uri") ||
652 !strcmp(attr
->name
, "marker-change-time") ||
653 !strcmp(attr
->name
, "marker-colors") ||
654 !strcmp(attr
->name
, "marker-high-levels") ||
655 !strcmp(attr
->name
, "marker-levels") ||
656 !strcmp(attr
->name
, "marker-low-levels") ||
657 !strcmp(attr
->name
, "marker-message") ||
658 !strcmp(attr
->name
, "marker-names") ||
659 !strcmp(attr
->name
, "marker-types") ||
660 !strcmp(attr
->name
, "printer-commands") ||
661 !strcmp(attr
->name
, "printer-info") ||
662 !strcmp(attr
->name
, "printer-is-shared") ||
663 !strcmp(attr
->name
, "printer-make-and-model") ||
664 !strcmp(attr
->name
, "printer-state") ||
665 !strcmp(attr
->name
, "printer-state-change-time") ||
666 !strcmp(attr
->name
, "printer-type") ||
667 !strcmp(attr
->name
, "printer-is-accepting-jobs") ||
668 !strcmp(attr
->name
, "printer-location") ||
669 !strcmp(attr
->name
, "printer-state-reasons") ||
670 !strcmp(attr
->name
, "printer-uri-supported"))
673 * Add a printer description attribute...
676 num_options
= cupsAddOption(attr
->name
,
677 cups_make_string(attr
, value
,
679 num_options
, &options
);
682 else if (!strcmp(attr
->name
, "media-supported"))
685 * See if we can set a default media size...
688 int i
; /* Looping var */
690 for (i
= 0; i
< attr
->num_values
; i
++)
691 if (!_cups_strcasecmp(media_default
, attr
->values
[i
].string
.text
))
693 num_options
= cupsAddOption("media", media_default
, num_options
,
698 #endif /* __APPLE__ */
699 else if (!strcmp(attr
->name
, "printer-name") &&
700 attr
->value_tag
== IPP_TAG_NAME
)
701 printer_name
= attr
->values
[0].string
.text
;
702 else if (strncmp(attr
->name
, "notify-", 7) &&
703 (attr
->value_tag
== IPP_TAG_BOOLEAN
||
704 attr
->value_tag
== IPP_TAG_ENUM
||
705 attr
->value_tag
== IPP_TAG_INTEGER
||
706 attr
->value_tag
== IPP_TAG_KEYWORD
||
707 attr
->value_tag
== IPP_TAG_NAME
||
708 attr
->value_tag
== IPP_TAG_RANGE
) &&
709 (ptr
= strstr(attr
->name
, "-default")) != NULL
)
712 * Add a default option...
715 strlcpy(optname
, attr
->name
, sizeof(optname
));
716 optname
[ptr
- attr
->name
] = '\0';
718 if (_cups_strcasecmp(optname
, "media") ||
719 !cupsGetOption("media", num_options
, options
))
720 num_options
= cupsAddOption(optname
,
721 cups_make_string(attr
, value
,
723 num_options
, &options
);
728 * See if we have everything needed...
733 cupsFreeOptions(num_options
, options
);
741 if ((dest
= cups_add_dest(printer_name
, NULL
, &num_dests
, dests
)) != NULL
)
743 dest
->num_options
= num_options
;
744 dest
->options
= options
;
747 cupsFreeOptions(num_options
, options
);
757 * Return the count...
765 * 'cupsGetDests()' - Get the list of destinations from the default server.
767 * Starting with CUPS 1.2, the returned list of destinations include the
768 * printer-info, printer-is-accepting-jobs, printer-is-shared,
769 * printer-make-and-model, printer-state, printer-state-change-time,
770 * printer-state-reasons, and printer-type attributes as options. CUPS 1.4
771 * adds the marker-change-time, marker-colors, marker-high-levels,
772 * marker-levels, marker-low-levels, marker-message, marker-names,
773 * marker-types, and printer-commands attributes as well.
775 * Use the @link cupsFreeDests@ function to free the destination list and
776 * the @link cupsGetDest@ function to find a particular destination.
779 int /* O - Number of destinations */
780 cupsGetDests(cups_dest_t
**dests
) /* O - Destinations */
782 return (cupsGetDests2(CUPS_HTTP_DEFAULT
, dests
));
787 * 'cupsGetDests2()' - Get the list of destinations from the specified server.
789 * Starting with CUPS 1.2, the returned list of destinations include the
790 * printer-info, printer-is-accepting-jobs, printer-is-shared,
791 * printer-make-and-model, printer-state, printer-state-change-time,
792 * printer-state-reasons, and printer-type attributes as options. CUPS 1.4
793 * adds the marker-change-time, marker-colors, marker-high-levels,
794 * marker-levels, marker-low-levels, marker-message, marker-names,
795 * marker-types, and printer-commands attributes as well.
797 * Use the @link cupsFreeDests@ function to free the destination list and
798 * the @link cupsGetDest@ function to find a particular destination.
800 * @since CUPS 1.1.21/Mac OS X 10.4@
803 int /* O - Number of destinations */
804 cupsGetDests2(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
805 cups_dest_t
**dests
) /* O - Destinations */
807 int i
; /* Looping var */
808 int num_dests
; /* Number of destinations */
809 cups_dest_t
*dest
; /* Destination pointer */
810 const char *home
; /* HOME environment variable */
811 char filename
[1024]; /* Local ~/.cups/lpoptions file */
812 const char *defprinter
; /* Default printer */
813 char name
[1024], /* Copy of printer name */
814 *instance
, /* Pointer to instance name */
815 *user_default
; /* User default printer */
816 int num_reals
; /* Number of real queues */
817 cups_dest_t
*reals
; /* Real queues */
818 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
822 * Range check the input...
827 _cupsSetError(IPP_INTERNAL_ERROR
, _("Bad NULL dests pointer"), 1);
832 * Grab the printers and classes...
835 *dests
= (cups_dest_t
*)0;
836 num_dests
= _cupsGetDests(http
, CUPS_GET_PRINTERS
, NULL
, dests
);
838 if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE
)
840 cupsFreeDests(num_dests
, *dests
);
841 *dests
= (cups_dest_t
*)0;
846 * Make a copy of the "real" queues for a later sanity check...
851 num_reals
= num_dests
;
852 reals
= calloc(num_reals
, sizeof(cups_dest_t
));
855 memcpy(reals
, *dests
, num_reals
* sizeof(cups_dest_t
));
866 * Grab the default destination...
869 if ((user_default
= _cupsUserDefault(name
, sizeof(name
))) != NULL
)
871 else if ((defprinter
= cupsGetDefault2(http
)) != NULL
)
873 strlcpy(name
, defprinter
, sizeof(name
));
880 * Separate printer and instance name...
883 if ((instance
= strchr(name
, '/')) != NULL
)
887 * Lookup the printer and instance and make it the default...
890 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
891 dest
->is_default
= 1;
897 * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
900 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
901 num_dests
= cups_get_dests(filename
, NULL
, NULL
, user_default
!= NULL
,
904 if ((home
= getenv("HOME")) != NULL
)
906 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
908 num_dests
= cups_get_dests(filename
, NULL
, NULL
, user_default
!= NULL
,
913 * Validate the current default destination - this prevents old
914 * Default lines in /etc/cups/lpoptions and ~/.cups/lpoptions from
915 * pointing to a non-existent printer or class...
921 * See if we have a default printer...
924 if ((dest
= cupsGetDest(NULL
, NULL
, num_dests
, *dests
)) != NULL
)
927 * Have a default; see if it is real...
930 dest
= cupsGetDest(dest
->name
, NULL
, num_reals
, reals
);
934 * If dest is NULL, then no default (that exists) is set, so we
935 * need to set a default if one exists...
938 if (dest
== NULL
&& defprinter
!= NULL
)
940 for (i
= 0; i
< num_dests
; i
++)
941 (*dests
)[i
].is_default
= 0;
943 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
944 dest
->is_default
= 1;
955 * Return the number of destinations...
959 _cupsSetError(IPP_OK
, NULL
, 0);
966 * 'cupsGetNamedDest()' - Get options for the named destination.
968 * This function is optimized for retrieving a single destination and should
969 * be used instead of @link cupsGetDests@ and @link cupsGetDest@ when you either
970 * know the name of the destination or want to print to the default destination.
971 * If @code NULL@ is returned, the destination does not exist or there is no
972 * default destination.
974 * If "http" is @code CUPS_HTTP_DEFAULT@, the connection to the default print
975 * server will be used.
977 * If "name" is @code NULL@, the default printer for the current user will be
980 * The returned destination must be freed using @link cupsFreeDests@ with a
981 * "num_dests" value of 1.
983 * @since CUPS 1.4/Mac OS X 10.6@
986 cups_dest_t
* /* O - Destination or @code NULL@ */
987 cupsGetNamedDest(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
988 const char *name
, /* I - Destination name or @code NULL@ for the default destination */
989 const char *instance
) /* I - Instance name or @code NULL@ */
991 cups_dest_t
*dest
; /* Destination */
992 char filename
[1024], /* Path to lpoptions */
993 defname
[256]; /* Default printer name */
994 const char *home
= getenv("HOME"); /* Home directory */
995 int set_as_default
= 0; /* Set returned destination as default */
996 ipp_op_t op
= IPP_GET_PRINTER_ATTRIBUTES
;
997 /* IPP operation to get server ops */
998 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1002 * If "name" is NULL, find the default destination...
1008 name
= _cupsUserDefault(defname
, sizeof(defname
));
1012 char *ptr
; /* Temporary pointer... */
1014 if ((ptr
= strchr(defname
, '/')) != NULL
)
1025 * No default in the environment, try the user's lpoptions files...
1028 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
1030 name
= cups_get_default(filename
, defname
, sizeof(defname
), &instance
);
1036 * Still not there? Try the system lpoptions file...
1039 snprintf(filename
, sizeof(filename
), "%s/lpoptions",
1040 cg
->cups_serverroot
);
1041 name
= cups_get_default(filename
, defname
, sizeof(defname
), &instance
);
1047 * No locally-set default destination, ask the server...
1050 op
= CUPS_GET_DEFAULT
;
1055 * Get the printer's attributes...
1058 if (!_cupsGetDests(http
, op
, name
, &dest
))
1060 if (op
== CUPS_GET_DEFAULT
|| (name
&& !set_as_default
))
1064 * The default printer from environment variables or from a
1065 * configuration file does not exist. Find out the real default.
1068 if (!_cupsGetDests(http
, CUPS_GET_DEFAULT
, NULL
, &dest
))
1073 dest
->instance
= _cupsStrAlloc(instance
);
1076 dest
->is_default
= 1;
1079 * Then add local options...
1082 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
1083 cups_get_dests(filename
, name
, instance
, 1, 1, &dest
);
1087 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
1089 cups_get_dests(filename
, name
, instance
, 1, 1, &dest
);
1093 * Return the result...
1101 * 'cupsRemoveDest()' - Remove a destination from the destination list.
1103 * Removing a destination/instance does not delete the class or printer
1104 * queue, merely the lpoptions for that destination/instance. Use the
1105 * @link cupsSetDests@ or @link cupsSetDests2@ functions to save the new
1106 * options for the user.
1108 * @since CUPS 1.3/Mac OS X 10.5@
1111 int /* O - New number of destinations */
1112 cupsRemoveDest(const char *name
, /* I - Destination name */
1113 const char *instance
, /* I - Instance name or @code NULL@ */
1114 int num_dests
, /* I - Number of destinations */
1115 cups_dest_t
**dests
) /* IO - Destinations */
1117 int i
; /* Index into destinations */
1118 cups_dest_t
*dest
; /* Pointer to destination */
1122 * Find the destination...
1125 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) == NULL
)
1132 _cupsStrFree(dest
->name
);
1133 _cupsStrFree(dest
->instance
);
1134 cupsFreeOptions(dest
->num_options
, dest
->options
);
1137 * Remove the destination from the array...
1145 memmove(dest
, dest
+ 1, (num_dests
- i
) * sizeof(cups_dest_t
));
1152 * 'cupsSetDefaultDest()' - Set the default destination.
1154 * @since CUPS 1.3/Mac OS X 10.5@
1159 const char *name
, /* I - Destination name */
1160 const char *instance
, /* I - Instance name or @code NULL@ */
1161 int num_dests
, /* I - Number of destinations */
1162 cups_dest_t
*dests
) /* I - Destinations */
1164 int i
; /* Looping var */
1165 cups_dest_t
*dest
; /* Current destination */
1169 * Range check input...
1172 if (!name
|| num_dests
<= 0 || !dests
)
1176 * Loop through the array and set the "is_default" flag for the matching
1180 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
1181 dest
->is_default
= !_cups_strcasecmp(name
, dest
->name
) &&
1182 ((!instance
&& !dest
->instance
) ||
1183 (instance
&& dest
->instance
&&
1184 !_cups_strcasecmp(instance
, dest
->instance
)));
1189 * 'cupsSetDests()' - Save the list of destinations for the default server.
1191 * This function saves the destinations to /etc/cups/lpoptions when run
1192 * as root and ~/.cups/lpoptions when run as a normal user.
1196 cupsSetDests(int num_dests
, /* I - Number of destinations */
1197 cups_dest_t
*dests
) /* I - Destinations */
1199 cupsSetDests2(CUPS_HTTP_DEFAULT
, num_dests
, dests
);
1204 * 'cupsSetDests2()' - Save the list of destinations for the specified server.
1206 * This function saves the destinations to /etc/cups/lpoptions when run
1207 * as root and ~/.cups/lpoptions when run as a normal user.
1209 * @since CUPS 1.1.21/Mac OS X 10.4@
1212 int /* O - 0 on success, -1 on error */
1213 cupsSetDests2(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
1214 int num_dests
, /* I - Number of destinations */
1215 cups_dest_t
*dests
) /* I - Destinations */
1217 int i
, j
; /* Looping vars */
1218 int wrote
; /* Wrote definition? */
1219 cups_dest_t
*dest
; /* Current destination */
1220 cups_option_t
*option
; /* Current option */
1221 _ipp_option_t
*match
; /* Matching attribute for option */
1222 FILE *fp
; /* File pointer */
1224 const char *home
; /* HOME environment variable */
1226 char filename
[1024]; /* lpoptions file */
1227 int num_temps
; /* Number of temporary destinations */
1228 cups_dest_t
*temps
, /* Temporary destinations */
1229 *temp
; /* Current temporary dest */
1230 const char *val
; /* Value of temporary option */
1231 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1235 * Range check the input...
1238 if (!num_dests
|| !dests
)
1242 * Get the server destinations...
1245 num_temps
= _cupsGetDests(http
, CUPS_GET_PRINTERS
, NULL
, &temps
);
1247 if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE
)
1249 cupsFreeDests(num_temps
, temps
);
1254 * Figure out which file to write to...
1257 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
1263 * Merge in server defaults...
1266 num_temps
= cups_get_dests(filename
, NULL
, NULL
, 0, num_temps
, &temps
);
1269 * Point to user defaults...
1272 if ((home
= getenv("HOME")) != NULL
)
1275 * Create ~/.cups subdirectory...
1278 snprintf(filename
, sizeof(filename
), "%s/.cups", home
);
1279 if (access(filename
, 0))
1280 mkdir(filename
, 0700);
1282 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
1288 * Try to open the file...
1291 if ((fp
= fopen(filename
, "w")) == NULL
)
1293 cupsFreeDests(num_temps
, temps
);
1299 * Set the permissions to 0644 when saving to the /etc/cups/lpoptions
1304 fchmod(fileno(fp
), 0644);
1308 * Write each printer; each line looks like:
1310 * Dest name[/instance] options
1311 * Default name[/instance] options
1314 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
1315 if (dest
->instance
!= NULL
|| dest
->num_options
!= 0 || dest
->is_default
)
1317 if (dest
->is_default
)
1319 fprintf(fp
, "Default %s", dest
->name
);
1321 fprintf(fp
, "/%s", dest
->instance
);
1328 if ((temp
= cupsGetDest(dest
->name
, dest
->instance
, num_temps
, temps
)) == NULL
)
1329 temp
= cupsGetDest(dest
->name
, NULL
, num_temps
, temps
);
1331 for (j
= dest
->num_options
, option
= dest
->options
; j
> 0; j
--, option
++)
1334 * See if this option is a printer attribute; if so, skip it...
1337 if ((match
= _ippFindOption(option
->name
)) != NULL
&&
1338 match
->group_tag
== IPP_TAG_PRINTER
)
1342 * See if the server/global options match these; if so, don't
1347 (val
= cupsGetOption(option
->name
, temp
->num_options
,
1348 temp
->options
)) != NULL
&&
1349 !_cups_strcasecmp(val
, option
->value
))
1353 * Options don't match, write to the file...
1358 fprintf(fp
, "Dest %s", dest
->name
);
1360 fprintf(fp
, "/%s", dest
->instance
);
1364 if (option
->value
[0])
1366 if (strchr(option
->value
, ' ') ||
1367 strchr(option
->value
, '\\') ||
1368 strchr(option
->value
, '\"') ||
1369 strchr(option
->value
, '\''))
1372 * Quote the value...
1375 fprintf(fp
, " %s=\"", option
->name
);
1377 for (val
= option
->value
; *val
; val
++)
1379 if (strchr("\"\'\\", *val
))
1390 * Store the literal value...
1393 fprintf(fp
, " %s=%s", option
->name
, option
->value
);
1397 fprintf(fp
, " %s", option
->name
);
1405 * Free the temporary destinations and close the file...
1408 cupsFreeDests(num_temps
, temps
);
1414 * Set the default printer for this location - this allows command-line
1415 * and GUI applications to share the same default destination...
1418 if ((dest
= cupsGetDest(NULL
, NULL
, num_dests
, dests
)) != NULL
)
1420 CFStringRef name
= CFStringCreateWithCString(kCFAllocatorDefault
,
1422 kCFStringEncodingUTF8
);
1423 /* Default printer name */
1427 _cupsAppleSetDefaultPrinter(name
);
1431 #endif /* __APPLE__ */
1433 #ifdef HAVE_NOTIFY_POST
1435 * Send a notification so that MacOS X applications can know about the
1439 notify_post("com.apple.printerListChange");
1440 #endif /* HAVE_NOTIFY_POST */
1447 * '_cupsUserDefault()' - Get the user default printer from environment
1448 * variables and location information.
1451 char * /* O - Default printer or NULL */
1452 _cupsUserDefault(char *name
, /* I - Name buffer */
1453 size_t namesize
) /* I - Size of name buffer */
1455 const char *env
; /* LPDEST or PRINTER env variable */
1457 CFStringRef locprinter
; /* Last printer as this location */
1458 #endif /* __APPLE__ */
1461 if ((env
= getenv("LPDEST")) == NULL
)
1462 if ((env
= getenv("PRINTER")) != NULL
&& !strcmp(env
, "lp"))
1467 strlcpy(name
, env
, namesize
);
1473 * Use location-based defaults if "use last printer" is selected in the
1474 * system preferences...
1477 if ((locprinter
= _cupsAppleCopyDefaultPrinter()) != NULL
)
1479 CFStringGetCString(locprinter
, name
, namesize
, kCFStringEncodingUTF8
);
1480 CFRelease(locprinter
);
1485 DEBUG_printf(("1_cupsUserDefault: Returning \"%s\".", name
));
1487 return (*name
? name
: NULL
);
1491 * No location-based defaults on this platform...
1496 #endif /* __APPLE__ */
1502 * 'appleCopyLocations()' - Copy the location history array.
1505 static CFArrayRef
/* O - Location array or NULL */
1506 appleCopyLocations(void)
1508 CFArrayRef locations
; /* Location array */
1512 * Look up the location array in the preferences...
1515 if ((locations
= CFPreferencesCopyAppValue(kLastUsedPrintersKey
,
1516 kCUPSPrintingPrefs
)) == NULL
)
1519 if (CFGetTypeID(locations
) != CFArrayGetTypeID())
1521 CFRelease(locations
);
1530 * 'appleCopyNetwork()' - Get the network ID for the current location.
1533 static CFStringRef
/* O - Network ID */
1534 appleCopyNetwork(void)
1536 SCDynamicStoreRef dynamicStore
; /* System configuration data */
1537 CFStringRef key
; /* Current network configuration key */
1538 CFDictionaryRef ip_dict
; /* Network configuration data */
1539 CFStringRef network
= NULL
; /* Current network ID */
1542 if ((dynamicStore
= SCDynamicStoreCreate(NULL
, CFSTR("libcups"), NULL
,
1546 * First use the IPv6 router address, if available, since that will generally
1547 * be a globally-unique link-local address.
1550 if ((key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(
1551 NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv6
)) != NULL
)
1553 if ((ip_dict
= SCDynamicStoreCopyValue(dynamicStore
, key
)) != NULL
)
1555 if ((network
= CFDictionaryGetValue(ip_dict
,
1556 kSCPropNetIPv6Router
)) != NULL
)
1566 * If that doesn't work, try the IPv4 router address. This isn't as unique
1567 * and will likely be a 10.x.y.z or 192.168.y.z address...
1572 if ((key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(
1573 NULL
, kSCDynamicStoreDomainState
, kSCEntNetIPv4
)) != NULL
)
1575 if ((ip_dict
= SCDynamicStoreCopyValue(dynamicStore
, key
)) != NULL
)
1577 if ((network
= CFDictionaryGetValue(ip_dict
,
1578 kSCPropNetIPv4Router
)) != NULL
)
1588 CFRelease(dynamicStore
);
1596 * 'appleGetPaperSize()' - Get the default paper size.
1599 char * /* O - Default paper size */
1600 appleGetPaperSize(char *name
, /* I - Paper size name buffer */
1601 int namesize
) /* I - Size of buffer */
1603 CFStringRef defaultPaperID
; /* Default paper ID */
1604 _pwg_media_t
*pwgmedia
; /* PWG media size */
1607 defaultPaperID
= _cupsAppleCopyDefaultPaperID();
1608 if (!defaultPaperID
||
1609 CFGetTypeID(defaultPaperID
) != CFStringGetTypeID() ||
1610 !CFStringGetCString(defaultPaperID
, name
, namesize
,
1611 kCFStringEncodingUTF8
))
1613 else if ((pwgmedia
= _pwgMediaForLegacy(name
)) != NULL
)
1614 strlcpy(name
, pwgmedia
->pwg
, namesize
);
1617 CFRelease(defaultPaperID
);
1624 * 'appleGetPrinter()' - Get a printer from the history array.
1627 static CFStringRef
/* O - Printer name or NULL */
1628 appleGetPrinter(CFArrayRef locations
, /* I - Location array */
1629 CFStringRef network
, /* I - Network name */
1630 CFIndex
*locindex
) /* O - Index in array */
1632 CFIndex i
, /* Looping var */
1633 count
; /* Number of locations */
1634 CFDictionaryRef location
; /* Current location */
1635 CFStringRef locnetwork
, /* Current network */
1636 locprinter
; /* Current printer */
1639 for (i
= 0, count
= CFArrayGetCount(locations
); i
< count
; i
++)
1640 if ((location
= CFArrayGetValueAtIndex(locations
, i
)) != NULL
&&
1641 CFGetTypeID(location
) == CFDictionaryGetTypeID())
1643 if ((locnetwork
= CFDictionaryGetValue(location
,
1644 kLocationNetworkKey
)) != NULL
&&
1645 CFGetTypeID(locnetwork
) == CFStringGetTypeID() &&
1646 CFStringCompare(network
, locnetwork
, 0) == kCFCompareEqualTo
&&
1647 (locprinter
= CFDictionaryGetValue(location
,
1648 kLocationPrinterIDKey
)) != NULL
&&
1649 CFGetTypeID(locprinter
) == CFStringGetTypeID())
1654 return (locprinter
);
1660 #endif /* __APPLE__ */
1664 * 'cups_add_dest()' - Add a destination to the array.
1666 * Unlike cupsAddDest(), this function does not check for duplicates.
1669 static cups_dest_t
* /* O - New destination */
1670 cups_add_dest(const char *name
, /* I - Name of destination */
1671 const char *instance
, /* I - Instance or NULL */
1672 int *num_dests
, /* IO - Number of destinations */
1673 cups_dest_t
**dests
) /* IO - Destinations */
1675 int insert
, /* Insertion point */
1676 diff
; /* Result of comparison */
1677 cups_dest_t
*dest
; /* Destination pointer */
1681 * Add new destination...
1684 if (*num_dests
== 0)
1685 dest
= malloc(sizeof(cups_dest_t
));
1687 dest
= realloc(*dests
, sizeof(cups_dest_t
) * (*num_dests
+ 1));
1695 * Find where to insert the destination...
1698 if (*num_dests
== 0)
1702 insert
= cups_find_dest(name
, instance
, *num_dests
, *dests
, *num_dests
- 1,
1710 * Move the array elements as needed...
1713 if (insert
< *num_dests
)
1714 memmove(*dests
+ insert
+ 1, *dests
+ insert
,
1715 (*num_dests
- insert
) * sizeof(cups_dest_t
));
1720 * Initialize the destination...
1723 dest
= *dests
+ insert
;
1724 dest
->name
= _cupsStrAlloc(name
);
1725 dest
->instance
= _cupsStrAlloc(instance
);
1726 dest
->is_default
= 0;
1727 dest
->num_options
= 0;
1728 dest
->options
= (cups_option_t
*)0;
1735 * 'cups_compare_dests()' - Compare two destinations.
1738 static int /* O - Result of comparison */
1739 cups_compare_dests(cups_dest_t
*a
, /* I - First destination */
1740 cups_dest_t
*b
) /* I - Second destination */
1742 int diff
; /* Difference */
1745 if ((diff
= _cups_strcasecmp(a
->name
, b
->name
)) != 0)
1747 else if (a
->instance
&& b
->instance
)
1748 return (_cups_strcasecmp(a
->instance
, b
->instance
));
1750 return ((a
->instance
&& !b
->instance
) - (!a
->instance
&& b
->instance
));
1755 * 'cups_find_dest()' - Find a destination using a binary search.
1758 static int /* O - Index of match */
1759 cups_find_dest(const char *name
, /* I - Destination name */
1760 const char *instance
, /* I - Instance or NULL */
1761 int num_dests
, /* I - Number of destinations */
1762 cups_dest_t
*dests
, /* I - Destinations */
1763 int prev
, /* I - Previous index */
1764 int *rdiff
) /* O - Difference of match */
1766 int left
, /* Low mark for binary search */
1767 right
, /* High mark for binary search */
1768 current
, /* Current index */
1769 diff
; /* Result of comparison */
1770 cups_dest_t key
; /* Search key */
1773 key
.name
= (char *)name
;
1774 key
.instance
= (char *)instance
;
1779 * Start search on either side of previous...
1782 if ((diff
= cups_compare_dests(&key
, dests
+ prev
)) == 0 ||
1783 (diff
< 0 && prev
== 0) ||
1784 (diff
> 0 && prev
== (num_dests
- 1)))
1792 * Start with previous on right side...
1801 * Start wih previous on left side...
1805 right
= num_dests
- 1;
1811 * Start search in the middle...
1815 right
= num_dests
- 1;
1820 current
= (left
+ right
) / 2;
1821 diff
= cups_compare_dests(&key
, dests
+ current
);
1830 while ((right
- left
) > 1);
1835 * Check the last 1 or 2 elements...
1838 if ((diff
= cups_compare_dests(&key
, dests
+ left
)) <= 0)
1842 diff
= cups_compare_dests(&key
, dests
+ right
);
1848 * Return the closest destination and the difference...
1858 * 'cups_get_default()' - Get the default destination from an lpoptions file.
1861 static char * /* O - Default destination or NULL */
1862 cups_get_default(const char *filename
, /* I - File to read */
1863 char *namebuf
, /* I - Name buffer */
1864 size_t namesize
, /* I - Size of name buffer */
1865 const char **instance
) /* I - Instance */
1867 cups_file_t
*fp
; /* lpoptions file */
1868 char line
[8192], /* Line from file */
1869 *value
, /* Value for line */
1870 *nameptr
; /* Pointer into name */
1871 int linenum
; /* Current line */
1876 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
1880 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
1882 if (!_cups_strcasecmp(line
, "default") && value
)
1884 strlcpy(namebuf
, value
, namesize
);
1886 if ((nameptr
= strchr(namebuf
, ' ')) != NULL
)
1888 if ((nameptr
= strchr(namebuf
, '\t')) != NULL
)
1891 if ((nameptr
= strchr(namebuf
, '/')) != NULL
)
1894 *instance
= nameptr
;
1902 return (*namebuf
? namebuf
: NULL
);
1907 * 'cups_get_dests()' - Get destinations from a file.
1910 static int /* O - Number of destinations */
1912 const char *filename
, /* I - File to read from */
1913 const char *match_name
, /* I - Destination name we want */
1914 const char *match_inst
, /* I - Instance name we want */
1915 int user_default_set
, /* I - User default printer set? */
1916 int num_dests
, /* I - Number of destinations */
1917 cups_dest_t
**dests
) /* IO - Destinations */
1919 int i
; /* Looping var */
1920 cups_dest_t
*dest
; /* Current destination */
1921 cups_file_t
*fp
; /* File pointer */
1922 char line
[8192], /* Line from file */
1923 *lineptr
, /* Pointer into line */
1924 *name
, /* Name of destination/option */
1925 *instance
; /* Instance of destination */
1926 int linenum
; /* Current line number */
1929 DEBUG_printf(("7cups_get_dests(filename=\"%s\", match_name=\"%s\", "
1930 "match_inst=\"%s\", user_default_set=%d, num_dests=%d, "
1931 "dests=%p)", filename
, match_name
, match_inst
,
1932 user_default_set
, num_dests
, dests
));
1935 * Try to open the file...
1938 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1942 * Read each printer; each line looks like:
1944 * Dest name[/instance] options
1945 * Default name[/instance] options
1950 while (cupsFileGetConf(fp
, line
, sizeof(line
), &lineptr
, &linenum
))
1953 * See what type of line it is...
1956 DEBUG_printf(("9cups_get_dests: linenum=%d line=\"%s\" lineptr=\"%s\"",
1957 linenum
, line
, lineptr
));
1959 if ((_cups_strcasecmp(line
, "dest") && _cups_strcasecmp(line
, "default")) || !lineptr
)
1961 DEBUG_puts("9cups_get_dests: Not a dest or default line...");
1968 * Search for an instance...
1971 while (!isspace(*lineptr
& 255) && *lineptr
&& *lineptr
!= '/')
1974 if (*lineptr
== '/')
1977 * Found an instance...
1984 * Search for an instance...
1987 while (!isspace(*lineptr
& 255) && *lineptr
)
1996 DEBUG_printf(("9cups_get_dests: name=\"%s\", instance=\"%s\"", name
,
2000 * See if the primary instance of the destination exists; if not,
2001 * ignore this entry and move on...
2006 if (_cups_strcasecmp(name
, match_name
) ||
2007 (!instance
&& match_inst
) ||
2008 (instance
&& !match_inst
) ||
2009 (instance
&& _cups_strcasecmp(instance
, match_inst
)))
2014 else if (cupsGetDest(name
, NULL
, num_dests
, *dests
) == NULL
)
2016 DEBUG_puts("9cups_get_dests: Not found!");
2022 * Add the destination...
2025 num_dests
= cupsAddDest(name
, instance
, num_dests
, dests
);
2027 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) == NULL
)
2033 DEBUG_puts("9cups_get_dests: Out of memory!");
2039 * Add options until we hit the end of the line...
2042 dest
->num_options
= cupsParseOptions(lineptr
, dest
->num_options
,
2046 * If we found what we were looking for, stop now...
2053 * Set this as default if needed...
2056 if (!user_default_set
&& !_cups_strcasecmp(line
, "default"))
2058 DEBUG_puts("9cups_get_dests: Setting as default...");
2060 for (i
= 0; i
< num_dests
; i
++)
2061 (*dests
)[i
].is_default
= 0;
2063 dest
->is_default
= 1;
2068 * Close the file and return...
2078 * 'cups_make_string()' - Make a comma-separated string of values from an IPP
2082 static char * /* O - New string */
2084 ipp_attribute_t
*attr
, /* I - Attribute to convert */
2085 char *buffer
, /* I - Buffer */
2086 size_t bufsize
) /* I - Size of buffer */
2088 int i
; /* Looping var */
2089 char *ptr
, /* Pointer into buffer */
2090 *end
, /* Pointer to end of buffer */
2091 *valptr
; /* Pointer into string attribute */
2095 * Return quickly if we have a single string value...
2098 if (attr
->num_values
== 1 &&
2099 attr
->value_tag
!= IPP_TAG_INTEGER
&&
2100 attr
->value_tag
!= IPP_TAG_ENUM
&&
2101 attr
->value_tag
!= IPP_TAG_BOOLEAN
&&
2102 attr
->value_tag
!= IPP_TAG_RANGE
)
2103 return (attr
->values
[0].string
.text
);
2106 * Copy the values to the string, separating with commas and escaping strings
2110 end
= buffer
+ bufsize
- 1;
2112 for (i
= 0, ptr
= buffer
; i
< attr
->num_values
&& ptr
< end
; i
++)
2117 switch (attr
->value_tag
)
2119 case IPP_TAG_INTEGER
:
2121 snprintf(ptr
, end
- ptr
+ 1, "%d", attr
->values
[i
].integer
);
2124 case IPP_TAG_BOOLEAN
:
2125 if (attr
->values
[i
].boolean
)
2126 strlcpy(ptr
, "true", end
- ptr
+ 1);
2128 strlcpy(ptr
, "false", end
- ptr
+ 1);
2131 case IPP_TAG_RANGE
:
2132 if (attr
->values
[i
].range
.lower
== attr
->values
[i
].range
.upper
)
2133 snprintf(ptr
, end
- ptr
+ 1, "%d", attr
->values
[i
].range
.lower
);
2135 snprintf(ptr
, end
- ptr
+ 1, "%d-%d", attr
->values
[i
].range
.lower
,
2136 attr
->values
[i
].range
.upper
);
2140 for (valptr
= attr
->values
[i
].string
.text
;
2141 *valptr
&& ptr
< end
;)
2143 if (strchr(" \t\n\\\'\"", *valptr
))
2145 if (ptr
>= (end
- 1))
2168 * End of "$Id: dest.c 9568 2011-02-25 06:13:56Z mike $".