#include "cups.h"
#include "language.h"
#include "string.h"
#include <stdlib.h>
#include <ctype.h>
#ifdef HAVE_NOTIFY_H
# include <notify.h>
#endif
static int cups_get_dests(const char *filename, int num_dests,
cups_dest_t **dests);
static int cups_get_sdests(ipp_op_t op, int num_dests,
cups_dest_t **dests);
int
cupsAddDest(const char *name,
const char *instance,
int num_dests,
cups_dest_t **dests)
{
int i;
cups_dest_t *dest;
if (name == NULL || dests == NULL)
return (0);
if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
return (num_dests);
if (num_dests == 0)
dest = malloc(sizeof(cups_dest_t));
else
dest = realloc(*dests, sizeof(cups_dest_t) * (num_dests + 1));
if (dest == NULL)
return (num_dests);
*dests = dest;
for (i = num_dests; i > 0; i --, dest ++)
if (strcasecmp(name, dest->name) < 0)
break;
else if (strcasecmp(name, dest->name) == 0 &&
instance != NULL && dest->instance != NULL &&
strcasecmp(instance, dest->instance) < 0)
break;
if (i > 0)
memmove(dest + 1, dest, i * sizeof(cups_dest_t));
dest->name = strdup(name);
dest->is_default = 0;
dest->num_options = 0;
dest->options = (cups_option_t *)0;
if (instance == NULL)
dest->instance = NULL;
else
dest->instance = strdup(instance);
return (num_dests + 1);
}
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 ++)
{
free(dest->name);
if (dest->instance)
free(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 comp;
if (num_dests == 0 || dests == NULL)
return (NULL);
if (name == NULL)
{
while (num_dests > 0)
{
if (dests->is_default)
return (dests);
num_dests --;
dests ++;
}
}
else
{
while (num_dests > 0)
{
if ((comp = strcasecmp(name, dests->name)) < 0)
return (NULL);
else if (comp == 0)
{
if ((instance == NULL && dests->instance == NULL) ||
(instance != NULL && dests->instance != NULL &&
strcasecmp(instance, dests->instance) == 0))
return (dests);
}
num_dests --;
dests ++;
}
}
return (NULL);
}
int
cupsGetDests(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;
int num_reals;
cups_dest_t *reals;
num_dests = 0;
*dests = (cups_dest_t *)0;
num_dests = cups_get_sdests(CUPS_GET_PRINTERS, num_dests, dests);
num_dests = cups_get_sdests(CUPS_GET_CLASSES, num_dests, dests);
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 ((defprinter = cupsGetDefault()) != NULL)
{
strlcpy(name, defprinter, sizeof(name));
if ((instance = strchr(name, '/')) != NULL)
*instance++ = '\0';
if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
dest->is_default = 1;
}
else
{
instance = NULL;
}
if ((home = getenv("CUPS_SERVERROOT")) != NULL)
{
snprintf(filename, sizeof(filename), "%s/lpoptions", home);
num_dests = cups_get_dests(filename, num_dests, dests);
}
else
num_dests = cups_get_dests(CUPS_SERVERROOT "/lpoptions", num_dests, dests);
if ((home = getenv("HOME")) != NULL)
{
snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
num_dests = cups_get_dests(filename, 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);
}
return (num_dests);
}
void
cupsSetDests(int num_dests,
cups_dest_t *dests)
{
int i, j;
int wrote;
cups_dest_t *dest;
cups_option_t *option;
FILE *fp;
const char *home;
char filename[1024];
int num_temps;
cups_dest_t *temps,
*temp;
const char *val;
num_temps = cups_get_sdests(CUPS_GET_PRINTERS, 0, &temps);
num_temps = cups_get_sdests(CUPS_GET_CLASSES, num_temps, &temps);
if ((home = getenv("CUPS_SERVERROOT")) != NULL)
snprintf(filename, sizeof(filename), "%s/lpoptions", home);
else
strcpy(filename, CUPS_SERVERROOT "/lpoptions");
#ifndef WIN32
if (getuid())
{
num_temps = cups_get_dests(filename, num_temps, &temps);
if ((home = getenv("HOME")) != NULL)
snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
}
#endif
if ((fp = fopen(filename, "w")) == NULL)
{
cupsFreeDests(num_temps, temps);
return;
}
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 (temp && (val = cupsGetOption(option->name, temp->num_options,
temp->options)) != NULL)
{
if (strcasecmp(val, option->value) == 0)
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, ' ') != NULL)
fprintf(fp, " %s=\"%s\"", option->name, option->value);
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 HAVE_NOTIFY_POST
notify_post("com.apple.printerListChange");
#endif
}
static int
cups_get_dests(const char *filename,
int num_dests,
cups_dest_t **dests)
{
int i;
cups_dest_t *dest;
FILE *fp;
char line[8192],
*lineptr,
*name,
*instance;
const char *printer;
if ((printer = getenv("LPDEST")) == NULL)
if ((printer = getenv("PRINTER")) != NULL)
if (strcmp(printer, "lp") == 0)
printer = NULL;
if ((fp = fopen(filename, "r")) == NULL)
return (num_dests);
while (fgets(line, sizeof(line), fp) != NULL)
{
if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4]))
lineptr = line + 4;
else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7]))
lineptr = line + 7;
else
continue;
while (isspace(*lineptr))
lineptr ++;
if (!*lineptr)
continue;
name = lineptr;
while (!isspace(*lineptr) && *lineptr && *lineptr != '/')
lineptr ++;
if (!*lineptr)
continue;
if (*lineptr == '/')
{
*lineptr++ = '\0';
instance = lineptr;
while (!isspace(*lineptr) && *lineptr)
lineptr ++;
}
else
instance = NULL;
*lineptr++ = '\0';
if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
continue;
num_dests = cupsAddDest(name, instance, num_dests, dests);
if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
{
fclose(fp);
return (num_dests);
}
dest->num_options = cupsParseOptions(lineptr, dest->num_options,
&(dest->options));
if (strncasecmp(line, "default", 7) == 0 && printer == NULL)
{
for (i = 0; i < num_dests; i ++)
(*dests)[i].is_default = 0;
dest->is_default = 1;
}
}
fclose(fp);
return (num_dests);
}
static int
cups_get_sdests(ipp_op_t op,
int num_dests,
cups_dest_t **dests)
{
cups_dest_t *dest;
http_t *http;
ipp_t *request,
*response;
ipp_attribute_t *attr;
cups_lang_t *language;
const char *name;
char job_sheets[1024];
static const char * const pattrs[] =
{
"printer-name",
"job-sheets-default"
};
if ((http = httpConnect(cupsServer(), ippPort())) == NULL)
return (num_dests);
request = ippNew();
request->request.op.operation_id = op;
request->request.op.request_id = 1;
language = cupsLangDefault();
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, cupsLangEncoding(language));
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
"requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
NULL, pattrs);
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;
name = NULL;
strcpy(job_sheets, "");
while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
{
if (strcmp(attr->name, "printer-name") == 0 &&
attr->value_tag == IPP_TAG_NAME)
name = attr->values[0].string.text;
if (strcmp(attr->name, "job-sheets-default") == 0 &&
(attr->value_tag == IPP_TAG_KEYWORD ||
attr->value_tag == IPP_TAG_NAME))
{
if (attr->num_values == 2)
snprintf(job_sheets, sizeof(job_sheets), "%s,%s",
attr->values[0].string.text, attr->values[1].string.text);
else
strcpy(job_sheets, attr->values[0].string.text);
}
attr = attr->next;
}
if (!name)
{
if (attr == NULL)
break;
else
continue;
}
num_dests = cupsAddDest(name, NULL, num_dests, dests);
if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL)
if (job_sheets[0])
dest->num_options = cupsAddOption("job-sheets", job_sheets, 0,
&(dest->options));
if (attr == NULL)
break;
}
ippDelete(response);
}
httpClose(http);
return (num_dests);
}