#include "cups-private.h"
#include <sys/stat.h>
#ifdef HAVE_NOTIFY_H
# include <notify.h>
#endif
#ifdef __APPLE__
# include <SystemConfiguration/SystemConfiguration.h>
# define kCUPSPrintingPrefs CFSTR("org.cups.PrintingPrefs")
# define kDefaultPaperIDKey CFSTR("DefaultPaperID")
# define kLastUsedPrintersKey CFSTR("LastUsedPrinters")
# define kLocationNetworkKey CFSTR("Network")
# define kLocationPrinterIDKey CFSTR("PrinterID")
# define kUseLastPrinter CFSTR("UseLastPrinter")
#endif
#ifdef __APPLE__
static CFArrayRef appleCopyLocations(void);
static CFStringRef appleCopyNetwork(void);
static char *appleGetPaperSize(char *name, int namesize);
static CFStringRef appleGetPrinter(CFArrayRef locations, CFStringRef network,
CFIndex *locindex);
#endif
static cups_dest_t *cups_add_dest(const char *name, const char *instance,
int *num_dests, cups_dest_t **dests);
static int cups_compare_dests(cups_dest_t *a, cups_dest_t *b);
static int cups_find_dest(const char *name, const char *instance,
int num_dests, cups_dest_t *dests, int prev,
int *rdiff);
static char *cups_get_default(const char *filename, char *namebuf,
size_t namesize, const char **instance);
static int cups_get_dests(const char *filename, const char *match_name,
const char *match_inst, int user_default_set,
int num_dests, cups_dest_t **dests);
static char *cups_make_string(ipp_attribute_t *attr, char *buffer,
size_t bufsize);
int
cupsAddDest(const char *name,
const char *instance,
int num_dests,
cups_dest_t **dests)
{
int i;
cups_dest_t *dest;
cups_dest_t *parent = NULL;
cups_option_t *doption,
*poption;
if (!name || !dests)
return (0);
if (!cupsGetDest(name, instance, num_dests, *dests))
{
if (instance && !cupsGetDest(name, NULL, num_dests, *dests))
return (num_dests);
dest = cups_add_dest(name, instance, &num_dests, dests);
parent = cupsGetDest(name, NULL, num_dests, *dests);
if (instance && parent && parent->num_options > 0)
{
dest->options = calloc(sizeof(cups_option_t), parent->num_options);
if (dest->options)
{
dest->num_options = parent->num_options;
for (i = dest->num_options, doption = dest->options,
poption = parent->options;
i > 0;
i --, doption ++, poption ++)
{
doption->name = _cupsStrRetain(poption->name);
doption->value = _cupsStrRetain(poption->value);
}
}
}
}
return (num_dests);
}
#ifdef __APPLE__
CFStringRef
_cupsAppleCopyDefaultPaperID(void)
{
return (CFPreferencesCopyAppValue(kDefaultPaperIDKey,
kCUPSPrintingPrefs));
}
CFStringRef
_cupsAppleCopyDefaultPrinter(void)
{
CFStringRef network;
CFArrayRef locations;
CFStringRef locprinter;
if (!_cupsAppleGetUseLastPrinter())
{
DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Not using last printer as "
"default.");
return (NULL);
}
if ((network = appleCopyNetwork()) == NULL)
{
DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Unable to get current "
"network.");
return (NULL);
}
if ((locations = appleCopyLocations()) == NULL)
{
DEBUG_puts("1_cupsAppleCopyDefaultPrinter: Missing or bad last used "
"printer array.");
CFRelease(network);
return (NULL);
}
DEBUG_printf(("1_cupsAppleCopyDefaultPrinter: Got locations, %d entries.",
(int)CFArrayGetCount(locations)));
if ((locprinter = appleGetPrinter(locations, network, NULL)) != NULL)
CFRetain(locprinter);
CFRelease(network);
CFRelease(locations);
return (locprinter);
}
int
_cupsAppleGetUseLastPrinter(void)
{
Boolean uselast,
uselast_set;
if (getenv("CUPS_DISABLE_APPLE_DEFAULT"))
return (0);
uselast = CFPreferencesGetAppBooleanValue(kUseLastPrinter,
kCUPSPrintingPrefs,
&uselast_set);
if (!uselast_set)
return (1);
else
return (uselast);
}
void
_cupsAppleSetDefaultPaperID(
CFStringRef name)
{
CFPreferencesSetAppValue(kDefaultPaperIDKey, name, kCUPSPrintingPrefs);
CFPreferencesAppSynchronize(kCUPSPrintingPrefs);
notify_post("com.apple.printerPrefsChange");
}
void
_cupsAppleSetDefaultPrinter(
CFStringRef name)
{
CFStringRef network;
CFArrayRef locations;
CFIndex locindex;
CFStringRef locprinter;
CFMutableArrayRef newlocations;
CFMutableDictionaryRef newlocation;
if ((network = appleCopyNetwork()) == NULL)
{
DEBUG_puts("1_cupsAppleSetDefaultPrinter: Unable to get current network...");
return;
}
if ((locations = appleCopyLocations()) != NULL)
locprinter = appleGetPrinter(locations, network, &locindex);
else
{
locprinter = NULL;
locindex = -1;
}
if (!locprinter || CFStringCompare(locprinter, name, 0) != kCFCompareEqualTo)
{
if (locations)
{
newlocations = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0,
locations);
if (locprinter)
CFArrayRemoveValueAtIndex(newlocations, locindex);
}
else
newlocations = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
newlocation = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (newlocation && newlocations)
{
CFDictionaryAddValue(newlocation, kLocationNetworkKey, network);
CFDictionaryAddValue(newlocation, kLocationPrinterIDKey, name);
CFArrayInsertValueAtIndex(newlocations, 0, newlocation);
while (CFArrayGetCount(newlocations) > 10)
CFArrayRemoveValueAtIndex(newlocations, 10);
CFPreferencesSetAppValue(kLastUsedPrintersKey, newlocations,
kCUPSPrintingPrefs);
CFPreferencesAppSynchronize(kCUPSPrintingPrefs);
notify_post("com.apple.printerPrefsChange");
}
if (newlocations)
CFRelease(newlocations);
if (newlocation)
CFRelease(newlocation);
}
if (locations)
CFRelease(locations);
CFRelease(network);
}
void
_cupsAppleSetUseLastPrinter(
int uselast)
{
CFPreferencesSetAppValue(kUseLastPrinter,
uselast ? kCFBooleanTrue : kCFBooleanFalse,
kCUPSPrintingPrefs);
CFPreferencesAppSynchronize(kCUPSPrintingPrefs);
notify_post("com.apple.printerPrefsChange");
}
#endif
void
cupsFreeDests(int num_dests,
cups_dest_t *dests)
{
int i;
cups_dest_t *dest;
if (num_dests == 0 || dests == NULL)
return;
for (i = num_dests, dest = dests; i > 0; i --, dest ++)
{
_cupsStrFree(dest->name);
_cupsStrFree(dest->instance);
cupsFreeOptions(dest->num_options, dest->options);
}
free(dests);
}
cups_dest_t *
cupsGetDest(const char *name,
const char *instance,
int num_dests,
cups_dest_t *dests)
{
int diff,
match;
if (num_dests <= 0 || !dests)
return (NULL);
if (!name)
{
while (num_dests > 0)
{
if (dests->is_default)
return (dests);
num_dests --;
dests ++;
}
}
else
{
match = cups_find_dest(name, instance, num_dests, dests, -1, &diff);
if (!diff)
return (dests + match);
}
return (NULL);
}
int
_cupsGetDests(http_t *http,
ipp_op_t op,
const char *name,
cups_dest_t **dests)
{
int num_dests = 0;
cups_dest_t *dest;
ipp_t *request,
*response;
ipp_attribute_t *attr;
const char *printer_name;
char uri[1024];
int num_options;
cups_option_t *options;
#ifdef __APPLE__
char media_default[41];
#endif
char optname[1024],
value[2048],
*ptr;
static const char * const pattrs[] =
{
"auth-info-required",
"device-uri",
"job-sheets-default",
"marker-change-time",
"marker-colors",
"marker-high-levels",
"marker-levels",
"marker-low-levels",
"marker-message",
"marker-names",
"marker-types",
#ifdef __APPLE__
"media-supported",
#endif
"printer-commands",
"printer-defaults",
"printer-info",
"printer-is-accepting-jobs",
"printer-is-shared",
"printer-location",
"printer-make-and-model",
"printer-name",
"printer-state",
"printer-state-change-time",
"printer-state-reasons",
"printer-type",
"printer-uri-supported"
};
#ifdef __APPLE__
appleGetPaperSize(media_default, sizeof(media_default));
#endif
request = ippNewRequest(op);
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
NULL, pattrs);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
"requesting-user-name", NULL, cupsUser());
if (name && op != CUPS_GET_DEFAULT)
{
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
"localhost", ippPort(), "/printers/%s", name);
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
uri);
}
if ((response = cupsDoRequest(http, request, "/")) != NULL)
{
for (attr = response->attrs; attr != NULL; attr = attr->next)
{
while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
attr = attr->next;
if (attr == NULL)
break;
printer_name = NULL;
num_options = 0;
options = NULL;
for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)
{
if (attr->value_tag != IPP_TAG_INTEGER &&
attr->value_tag != IPP_TAG_ENUM &&
attr->value_tag != IPP_TAG_BOOLEAN &&
attr->value_tag != IPP_TAG_TEXT &&
attr->value_tag != IPP_TAG_TEXTLANG &&
attr->value_tag != IPP_TAG_NAME &&
attr->value_tag != IPP_TAG_NAMELANG &&
attr->value_tag != IPP_TAG_KEYWORD &&
attr->value_tag != IPP_TAG_RANGE &&
attr->value_tag != IPP_TAG_URI)
continue;
if (!strcmp(attr->name, "auth-info-required") ||
!strcmp(attr->name, "device-uri") ||
!strcmp(attr->name, "marker-change-time") ||
!strcmp(attr->name, "marker-colors") ||
!strcmp(attr->name, "marker-high-levels") ||
!strcmp(attr->name, "marker-levels") ||
!strcmp(attr->name, "marker-low-levels") ||
!strcmp(attr->name, "marker-message") ||
!strcmp(attr->name, "marker-names") ||
!strcmp(attr->name, "marker-types") ||
!strcmp(attr->name, "printer-commands") ||
!strcmp(attr->name, "printer-info") ||
!strcmp(attr->name, "printer-is-shared") ||
!strcmp(attr->name, "printer-make-and-model") ||
!strcmp(attr->name, "printer-state") ||
!strcmp(attr->name, "printer-state-change-time") ||
!strcmp(attr->name, "printer-type") ||
!strcmp(attr->name, "printer-is-accepting-jobs") ||
!strcmp(attr->name, "printer-location") ||
!strcmp(attr->name, "printer-state-reasons") ||
!strcmp(attr->name, "printer-uri-supported"))
{
num_options = cupsAddOption(attr->name,
cups_make_string(attr, value,
sizeof(value)),
num_options, &options);
}
#ifdef __APPLE__
else if (!strcmp(attr->name, "media-supported"))
{
int i;
for (i = 0; i < attr->num_values; i ++)
if (!_cups_strcasecmp(media_default, attr->values[i].string.text))
{
num_options = cupsAddOption("media", media_default, num_options,
&options);
break;
}
}
#endif
else if (!strcmp(attr->name, "printer-name") &&
attr->value_tag == IPP_TAG_NAME)
printer_name = attr->values[0].string.text;
else if (strncmp(attr->name, "notify-", 7) &&
(attr->value_tag == IPP_TAG_BOOLEAN ||
attr->value_tag == IPP_TAG_ENUM ||
attr->value_tag == IPP_TAG_INTEGER ||
attr->value_tag == IPP_TAG_KEYWORD ||
attr->value_tag == IPP_TAG_NAME ||
attr->value_tag == IPP_TAG_RANGE) &&
(ptr = strstr(attr->name, "-default")) != NULL)
{
strlcpy(optname, attr->name, sizeof(optname));
optname[ptr - attr->name] = '\0';
if (_cups_strcasecmp(optname, "media") ||
!cupsGetOption("media", num_options, options))
num_options = cupsAddOption(optname,
cups_make_string(attr, value,
sizeof(value)),
num_options, &options);
}
}
if (!printer_name)
{
cupsFreeOptions(num_options, options);
if (attr == NULL)
break;
else
continue;
}
if ((dest = cups_add_dest(printer_name, NULL, &num_dests, dests)) != NULL)
{
dest->num_options = num_options;
dest->options = options;
}
else
cupsFreeOptions(num_options, options);
if (attr == NULL)
break;
}
ippDelete(response);
}
return (num_dests);
}
int
cupsGetDests(cups_dest_t **dests)
{
return (cupsGetDests2(CUPS_HTTP_DEFAULT, dests));
}
int
cupsGetDests2(http_t *http,
cups_dest_t **dests)
{
int i;
int num_dests;
cups_dest_t *dest;
const char *home;
char filename[1024];
const char *defprinter;
char name[1024],
*instance,
*user_default;
int num_reals;
cups_dest_t *reals;
_cups_globals_t *cg = _cupsGlobals();
if (!dests)
{
_cupsSetError(IPP_INTERNAL_ERROR, _("Bad NULL dests pointer"), 1);
return (0);
}
*dests = (cups_dest_t *)0;
num_dests = _cupsGetDests(http, CUPS_GET_PRINTERS, NULL, dests);
if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
{
cupsFreeDests(num_dests, *dests);
*dests = (cups_dest_t *)0;
return (0);
}
if (num_dests > 0)
{
num_reals = num_dests;
reals = calloc(num_reals, sizeof(cups_dest_t));
if (reals)
memcpy(reals, *dests, num_reals * sizeof(cups_dest_t));
else
num_reals = 0;
}
else
{
num_reals = 0;
reals = NULL;
}
if ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL)
defprinter = name;
else if ((defprinter = cupsGetDefault2(http)) != NULL)
{
strlcpy(name, defprinter, sizeof(name));
defprinter = name;
}
if (defprinter)
{
if ((instance = strchr(name, '/')) != NULL)
*instance++ = '\0';
if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
dest->is_default = 1;
}
else
instance = NULL;
snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL,
num_dests, dests);
if ((home = getenv("HOME")) != NULL)
{
snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL,
num_dests, dests);
}
if (num_reals)
{
if ((dest = cupsGetDest(NULL, NULL, num_dests, *dests)) != NULL)
{
dest = cupsGetDest(dest->name, NULL, num_reals, reals);
}
if (dest == NULL && defprinter != NULL)
{
for (i = 0; i < num_dests; i ++)
(*dests)[i].is_default = 0;
if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
dest->is_default = 1;
}
free(reals);
}
if (num_dests > 0)
_cupsSetError(IPP_OK, NULL, 0);
return (num_dests);
}
cups_dest_t *
cupsGetNamedDest(http_t *http,
const char *name,
const char *instance)
{
cups_dest_t *dest;
char filename[1024],
defname[256];
const char *home = getenv("HOME");
int set_as_default = 0;
ipp_op_t op = IPP_GET_PRINTER_ATTRIBUTES;
_cups_globals_t *cg = _cupsGlobals();
if (!name)
{
set_as_default = 1;
name = _cupsUserDefault(defname, sizeof(defname));
if (name)
{
char *ptr;
if ((ptr = strchr(defname, '/')) != NULL)
{
*ptr++ = '\0';
instance = ptr;
}
else
instance = NULL;
}
else if (home)
{
snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
name = cups_get_default(filename, defname, sizeof(defname), &instance);
}
if (!name)
{
snprintf(filename, sizeof(filename), "%s/lpoptions",
cg->cups_serverroot);
name = cups_get_default(filename, defname, sizeof(defname), &instance);
}
if (!name)
{
op = CUPS_GET_DEFAULT;
}
}
if (!_cupsGetDests(http, op, name, &dest))
{
if (op == CUPS_GET_DEFAULT || (name && !set_as_default))
return (NULL);
if (!_cupsGetDests(http, CUPS_GET_DEFAULT, NULL, &dest))
return (NULL);
}
if (instance)
dest->instance = _cupsStrAlloc(instance);
if (set_as_default)
dest->is_default = 1;
snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
cups_get_dests(filename, name, instance, 1, 1, &dest);
if (home)
{
snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
cups_get_dests(filename, name, instance, 1, 1, &dest);
}
return (dest);
}
int
cupsRemoveDest(const char *name,
const char *instance,
int num_dests,
cups_dest_t **dests)
{
int i;
cups_dest_t *dest;
if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
return (num_dests);
_cupsStrFree(dest->name);
_cupsStrFree(dest->instance);
cupsFreeOptions(dest->num_options, dest->options);
num_dests --;
i = dest - *dests;
if (i < num_dests)
memmove(dest, dest + 1, (num_dests - i) * sizeof(cups_dest_t));
return (num_dests);
}
void
cupsSetDefaultDest(
const char *name,
const char *instance,
int num_dests,
cups_dest_t *dests)
{
int i;
cups_dest_t *dest;
if (!name || num_dests <= 0 || !dests)
return;
for (i = num_dests, dest = dests; i > 0; i --, dest ++)
dest->is_default = !_cups_strcasecmp(name, dest->name) &&
((!instance && !dest->instance) ||
(instance && dest->instance &&
!_cups_strcasecmp(instance, dest->instance)));
}
void
cupsSetDests(int num_dests,
cups_dest_t *dests)
{
cupsSetDests2(CUPS_HTTP_DEFAULT, num_dests, dests);
}
int
cupsSetDests2(http_t *http,
int num_dests,
cups_dest_t *dests)
{
int i, j;
int wrote;
cups_dest_t *dest;
cups_option_t *option;
_ipp_option_t *match;
FILE *fp;
#ifndef WIN32
const char *home;
#endif
char filename[1024];
int num_temps;
cups_dest_t *temps,
*temp;
const char *val;
_cups_globals_t *cg = _cupsGlobals();
if (!num_dests || !dests)
return (-1);
num_temps = _cupsGetDests(http, CUPS_GET_PRINTERS, NULL, &temps);
if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
{
cupsFreeDests(num_temps, temps);
return (-1);
}
snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
#ifndef WIN32
if (getuid())
{
num_temps = cups_get_dests(filename, NULL, NULL, 0, num_temps, &temps);
if ((home = getenv("HOME")) != NULL)
{
snprintf(filename, sizeof(filename), "%s/.cups", home);
if (access(filename, 0))
mkdir(filename, 0700);
snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
}
}
#endif
if ((fp = fopen(filename, "w")) == NULL)
{
cupsFreeDests(num_temps, temps);
return (-1);
}
#ifndef WIN32
if (!getuid())
fchmod(fileno(fp), 0644);
#endif
for (i = num_dests, dest = dests; i > 0; i --, dest ++)
if (dest->instance != NULL || dest->num_options != 0 || dest->is_default)
{
if (dest->is_default)
{
fprintf(fp, "Default %s", dest->name);
if (dest->instance)
fprintf(fp, "/%s", dest->instance);
wrote = 1;
}
else
wrote = 0;
if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
temp = cupsGetDest(dest->name, NULL, num_temps, temps);
for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
{
if ((match = _ippFindOption(option->name)) != NULL &&
match->group_tag == IPP_TAG_PRINTER)
continue;
if (temp &&
(val = cupsGetOption(option->name, temp->num_options,
temp->options)) != NULL &&
!_cups_strcasecmp(val, option->value))
continue;
if (!wrote)
{
fprintf(fp, "Dest %s", dest->name);
if (dest->instance)
fprintf(fp, "/%s", dest->instance);
wrote = 1;
}
if (option->value[0])
{
if (strchr(option->value, ' ') ||
strchr(option->value, '\\') ||
strchr(option->value, '\"') ||
strchr(option->value, '\''))
{
fprintf(fp, " %s=\"", option->name);
for (val = option->value; *val; val ++)
{
if (strchr("\"\'\\", *val))
putc('\\', fp);
putc(*val, fp);
}
putc('\"', fp);
}
else
{
fprintf(fp, " %s=%s", option->name, option->value);
}
}
else
fprintf(fp, " %s", option->name);
}
if (wrote)
fputs("\n", fp);
}
cupsFreeDests(num_temps, temps);
fclose(fp);
#ifdef __APPLE__
if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
{
CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault,
dest->name,
kCFStringEncodingUTF8);
if (name)
{
_cupsAppleSetDefaultPrinter(name);
CFRelease(name);
}
}
#endif
#ifdef HAVE_NOTIFY_POST
notify_post("com.apple.printerListChange");
#endif
return (0);
}
char *
_cupsUserDefault(char *name,
size_t namesize)
{
const char *env;
#ifdef __APPLE__
CFStringRef locprinter;
#endif
if ((env = getenv("LPDEST")) == NULL)
if ((env = getenv("PRINTER")) != NULL && !strcmp(env, "lp"))
env = NULL;
if (env)
{
strlcpy(name, env, namesize);
return (name);
}
#ifdef __APPLE__
if ((locprinter = _cupsAppleCopyDefaultPrinter()) != NULL)
{
CFStringGetCString(locprinter, name, namesize, kCFStringEncodingUTF8);
CFRelease(locprinter);
}
else
name[0] = '\0';
DEBUG_printf(("1_cupsUserDefault: Returning \"%s\".", name));
return (*name ? name : NULL);
#else
name[0] = '\0';
return (NULL);
#endif
}
#ifdef __APPLE__
static CFArrayRef
appleCopyLocations(void)
{
CFArrayRef locations;
if ((locations = CFPreferencesCopyAppValue(kLastUsedPrintersKey,
kCUPSPrintingPrefs)) == NULL)
return (NULL);
if (CFGetTypeID(locations) != CFArrayGetTypeID())
{
CFRelease(locations);
return (NULL);
}
return (locations);
}
static CFStringRef
appleCopyNetwork(void)
{
SCDynamicStoreRef dynamicStore;
CFStringRef key;
CFDictionaryRef ip_dict;
CFStringRef network = NULL;
if ((dynamicStore = SCDynamicStoreCreate(NULL, CFSTR("libcups"), NULL,
NULL)) != NULL)
{
if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6)) != NULL)
{
if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
{
if ((network = CFDictionaryGetValue(ip_dict,
kSCPropNetIPv6Router)) != NULL)
CFRetain(network);
CFRelease(ip_dict);
}
CFRelease(key);
}
if (!network)
{
if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)) != NULL)
{
if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
{
if ((network = CFDictionaryGetValue(ip_dict,
kSCPropNetIPv4Router)) != NULL)
CFRetain(network);
CFRelease(ip_dict);
}
CFRelease(key);
}
}
CFRelease(dynamicStore);
}
return (network);
}
char *
appleGetPaperSize(char *name,
int namesize)
{
CFStringRef defaultPaperID;
_pwg_media_t *pwgmedia;
defaultPaperID = _cupsAppleCopyDefaultPaperID();
if (!defaultPaperID ||
CFGetTypeID(defaultPaperID) != CFStringGetTypeID() ||
!CFStringGetCString(defaultPaperID, name, namesize,
kCFStringEncodingUTF8))
name[0] = '\0';
else if ((pwgmedia = _pwgMediaForLegacy(name)) != NULL)
strlcpy(name, pwgmedia->pwg, namesize);
if (defaultPaperID)
CFRelease(defaultPaperID);
return (name);
}
static CFStringRef
appleGetPrinter(CFArrayRef locations,
CFStringRef network,
CFIndex *locindex)
{
CFIndex i,
count;
CFDictionaryRef location;
CFStringRef locnetwork,
locprinter;
for (i = 0, count = CFArrayGetCount(locations); i < count; i ++)
if ((location = CFArrayGetValueAtIndex(locations, i)) != NULL &&
CFGetTypeID(location) == CFDictionaryGetTypeID())
{
if ((locnetwork = CFDictionaryGetValue(location,
kLocationNetworkKey)) != NULL &&
CFGetTypeID(locnetwork) == CFStringGetTypeID() &&
CFStringCompare(network, locnetwork, 0) == kCFCompareEqualTo &&
(locprinter = CFDictionaryGetValue(location,
kLocationPrinterIDKey)) != NULL &&
CFGetTypeID(locprinter) == CFStringGetTypeID())
{
if (locindex)
*locindex = i;
return (locprinter);
}
}
return (NULL);
}
#endif
static cups_dest_t *
cups_add_dest(const char *name,
const char *instance,
int *num_dests,
cups_dest_t **dests)
{
int insert,
diff;
cups_dest_t *dest;
if (*num_dests == 0)
dest = malloc(sizeof(cups_dest_t));
else
dest = realloc(*dests, sizeof(cups_dest_t) * (*num_dests + 1));
if (!dest)
return (NULL);
*dests = dest;
if (*num_dests == 0)
insert = 0;
else
{
insert = cups_find_dest(name, instance, *num_dests, *dests, *num_dests - 1,
&diff);
if (diff > 0)
insert ++;
}
if (insert < *num_dests)
memmove(*dests + insert + 1, *dests + insert,
(*num_dests - insert) * sizeof(cups_dest_t));
(*num_dests) ++;
dest = *dests + insert;
dest->name = _cupsStrAlloc(name);
dest->instance = _cupsStrAlloc(instance);
dest->is_default = 0;
dest->num_options = 0;
dest->options = (cups_option_t *)0;
return (dest);
}
static int
cups_compare_dests(cups_dest_t *a,
cups_dest_t *b)
{
int diff;
if ((diff = _cups_strcasecmp(a->name, b->name)) != 0)
return (diff);
else if (a->instance && b->instance)
return (_cups_strcasecmp(a->instance, b->instance));
else
return ((a->instance && !b->instance) - (!a->instance && b->instance));
}
static int
cups_find_dest(const char *name,
const char *instance,
int num_dests,
cups_dest_t *dests,
int prev,
int *rdiff)
{
int left,
right,
current,
diff;
cups_dest_t key;
key.name = (char *)name;
key.instance = (char *)instance;
if (prev >= 0)
{
if ((diff = cups_compare_dests(&key, dests + prev)) == 0 ||
(diff < 0 && prev == 0) ||
(diff > 0 && prev == (num_dests - 1)))
{
*rdiff = diff;
return (prev);
}
else if (diff < 0)
{
left = 0;
right = prev;
}
else
{
left = prev;
right = num_dests - 1;
}
}
else
{
left = 0;
right = num_dests - 1;
}
do
{
current = (left + right) / 2;
diff = cups_compare_dests(&key, dests + current);
if (diff == 0)
break;
else if (diff < 0)
right = current;
else
left = current;
}
while ((right - left) > 1);
if (diff != 0)
{
if ((diff = cups_compare_dests(&key, dests + left)) <= 0)
current = left;
else
{
diff = cups_compare_dests(&key, dests + right);
current = right;
}
}
*rdiff = diff;
return (current);
}
static char *
cups_get_default(const char *filename,
char *namebuf,
size_t namesize,
const char **instance)
{
cups_file_t *fp;
char line[8192],
*value,
*nameptr;
int linenum;
*namebuf = '\0';
if ((fp = cupsFileOpen(filename, "r")) != NULL)
{
linenum = 0;
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
{
if (!_cups_strcasecmp(line, "default") && value)
{
strlcpy(namebuf, value, namesize);
if ((nameptr = strchr(namebuf, ' ')) != NULL)
*nameptr = '\0';
if ((nameptr = strchr(namebuf, '\t')) != NULL)
*nameptr = '\0';
if ((nameptr = strchr(namebuf, '/')) != NULL)
*nameptr++ = '\0';
*instance = nameptr;
break;
}
}
cupsFileClose(fp);
}
return (*namebuf ? namebuf : NULL);
}
static int
cups_get_dests(
const char *filename,
const char *match_name,
const char *match_inst,
int user_default_set,
int num_dests,
cups_dest_t **dests)
{
int i;
cups_dest_t *dest;
cups_file_t *fp;
char line[8192],
*lineptr,
*name,
*instance;
int linenum;
DEBUG_printf(("7cups_get_dests(filename=\"%s\", match_name=\"%s\", "
"match_inst=\"%s\", user_default_set=%d, num_dests=%d, "
"dests=%p)", filename, match_name, match_inst,
user_default_set, num_dests, dests));
if ((fp = cupsFileOpen(filename, "r")) == NULL)
return (num_dests);
linenum = 0;
while (cupsFileGetConf(fp, line, sizeof(line), &lineptr, &linenum))
{
DEBUG_printf(("9cups_get_dests: linenum=%d line=\"%s\" lineptr=\"%s\"",
linenum, line, lineptr));
if ((_cups_strcasecmp(line, "dest") && _cups_strcasecmp(line, "default")) || !lineptr)
{
DEBUG_puts("9cups_get_dests: Not a dest or default line...");
continue;
}
name = lineptr;
while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
lineptr ++;
if (*lineptr == '/')
{
*lineptr++ = '\0';
instance = lineptr;
while (!isspace(*lineptr & 255) && *lineptr)
lineptr ++;
}
else
instance = NULL;
if (*lineptr)
*lineptr++ = '\0';
DEBUG_printf(("9cups_get_dests: name=\"%s\", instance=\"%s\"", name,
instance));
if (match_name)
{
if (_cups_strcasecmp(name, match_name) ||
(!instance && match_inst) ||
(instance && !match_inst) ||
(instance && _cups_strcasecmp(instance, match_inst)))
continue;
dest = *dests;
}
else if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
{
DEBUG_puts("9cups_get_dests: Not found!");
continue;
}
else
{
num_dests = cupsAddDest(name, instance, num_dests, dests);
if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
{
DEBUG_puts("9cups_get_dests: Out of memory!");
break;
}
}
dest->num_options = cupsParseOptions(lineptr, dest->num_options,
&(dest->options));
if (match_name)
break;
if (!user_default_set && !_cups_strcasecmp(line, "default"))
{
DEBUG_puts("9cups_get_dests: Setting as default...");
for (i = 0; i < num_dests; i ++)
(*dests)[i].is_default = 0;
dest->is_default = 1;
}
}
cupsFileClose(fp);
return (num_dests);
}
static char *
cups_make_string(
ipp_attribute_t *attr,
char *buffer,
size_t bufsize)
{
int i;
char *ptr,
*end,
*valptr;
if (attr->num_values == 1 &&
attr->value_tag != IPP_TAG_INTEGER &&
attr->value_tag != IPP_TAG_ENUM &&
attr->value_tag != IPP_TAG_BOOLEAN &&
attr->value_tag != IPP_TAG_RANGE)
return (attr->values[0].string.text);
end = buffer + bufsize - 1;
for (i = 0, ptr = buffer; i < attr->num_values && ptr < end; i ++)
{
if (i)
*ptr++ = ',';
switch (attr->value_tag)
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
snprintf(ptr, end - ptr + 1, "%d", attr->values[i].integer);
break;
case IPP_TAG_BOOLEAN :
if (attr->values[i].boolean)
strlcpy(ptr, "true", end - ptr + 1);
else
strlcpy(ptr, "false", end - ptr + 1);
break;
case IPP_TAG_RANGE :
if (attr->values[i].range.lower == attr->values[i].range.upper)
snprintf(ptr, end - ptr + 1, "%d", attr->values[i].range.lower);
else
snprintf(ptr, end - ptr + 1, "%d-%d", attr->values[i].range.lower,
attr->values[i].range.upper);
break;
default :
for (valptr = attr->values[i].string.text;
*valptr && ptr < end;)
{
if (strchr(" \t\n\\\'\"", *valptr))
{
if (ptr >= (end - 1))
break;
*ptr++ = '\\';
}
*ptr++ = *valptr++;
}
*ptr = '\0';
break;
}
ptr += strlen(ptr);
}
*ptr = '\0';
return (buffer);
}