/*
- * "$Id$"
- *
* Sample IPP Everywhere server for CUPS.
*
* Copyright 2010-2015 by Apple Inc.
_IPP_PREASON_TONER_LOW = 0x8000 /* toner-low */
};
typedef unsigned int _ipp_preason_t; /* Bitfield for printer-state-reasons */
+static const char * const _ipp_preason_strings[] =
+{ /* Strings for each bit */
+ /* "none" is implied for no bits set */
+ "other",
+ "cover-open",
+ "input-tray-missing",
+ "marker-supply-empty",
+ "marker-supply-low",
+ "marker-waste-almost-full",
+ "marker-waste-full",
+ "media-empty",
+ "media-jam",
+ "media-low",
+ "media-needed",
+ "moving-to-paused",
+ "paused",
+ "spool-area-full",
+ "toner-empty",
+ "toner-low"
+};
typedef enum _ipp_media_class_e
{
"Toner Waste"
};
+/*
+ * URL scheme for web resources...
+ */
+
+#ifdef HAVE_SSL
+# define WEB_SCHEME "https"
+#else
+# define WEB_SCHEME "http"
+#endif /* HAVE_SSL */
+
/*
* Structures...
static void ipp_validate_job(_ipp_client_t *client);
static void load_attributes(const char *filename, ipp_t *attrs);
static int parse_options(_ipp_client_t *client, cups_option_t **options);
+static void process_attr_message(_ipp_job_t *job, char *message);
static void *process_client(_ipp_client_t *client);
static int process_http(_ipp_client_t *client);
static int process_ipp(_ipp_client_t *client);
static void *process_job(_ipp_job_t *job);
+static void process_state_message(_ipp_job_t *job, char *message);
static int register_printer(_ipp_printer_t *printer, const char *location, const char *make, const char *model, const char *formats, const char *adminurl, const char *uuid, int color, int duplex, const char *regtype);
static int respond_http(_ipp_client_t *client, http_status_t code,
const char *content_coding,
#ifdef WIN32
if ((tmpdir = getenv("TEMP")) == NULL)
tmpdir = "C:/TEMP";
-#elif defined(__APPLE__)
+#elif defined(__APPLE__) && !TARGET_OS_IOS
if ((tmpdir = getenv("TMPDIR")) == NULL)
tmpdir = "/private/tmp";
#else
ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id);
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, uri);
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, uuid);
- ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, client->printer->uri);
+ if ((attr = ippFindAttribute(client->request, "printer-uri", IPP_TAG_URI)) != NULL)
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, ippGetString(attr, 0, NULL));
+ else
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, client->printer->uri);
ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)(job->created - client->printer->start_time));
cupsArrayAdd(client->printer->jobs, job);
* Prepare values for the printer attributes...
*/
-#ifdef HAVE_SSL
-# define WEB_SCHEME "https"
-#else
-# define WEB_SCHEME "http"
-#endif /* HAVE_SSL */
-
httpAssembleURI(HTTP_URI_CODING_ALL, icons, sizeof(icons), WEB_SCHEME, NULL, printer->hostname, printer->port, "/icon.png");
httpAssembleURI(HTTP_URI_CODING_ALL, adminurl, sizeof(adminurl), WEB_SCHEME, NULL, printer->hostname, printer->port, "/");
httpAssembleURI(HTTP_URI_CODING_ALL, supplyurl, sizeof(supplyurl), WEB_SCHEME, NULL, printer->hostname, printer->port, "/supplies");
if (!ippFindAttribute(printer->attrs, "job-password-supported", IPP_TAG_ZERO))
ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-password-supported", 4);
- /* job-preferred-attributes-supported */
- ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-preferred-attributes-supported", 0);
-
/* job-priority-default */
if (!ippFindAttribute(printer->attrs, "job-priority-default", IPP_TAG_ZERO))
ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-default", 50);
if (!ippFindAttribute(printer->attrs, "pdl-override-supported", IPP_TAG_ZERO))
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pdl-override-supported", NULL, "attempted");
+ /* preferred-attributes-supported */
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "preferred-attributes-supported", 0);
+
/* print-color-mode-default */
if (!ippFindAttribute(printer->attrs, "print-color-mode-default", IPP_TAG_ZERO))
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, "auto");
"printer-state-reasons", NULL, "none");
else
{
- int num_reasons = 0;/* Number of reasons */
- const char *reasons[32]; /* Reason strings */
-
- if (printer->state_reasons & _IPP_PREASON_OTHER)
- reasons[num_reasons ++] = "other";
- if (printer->state_reasons & _IPP_PREASON_COVER_OPEN)
- reasons[num_reasons ++] = "cover-open";
- if (printer->state_reasons & _IPP_PREASON_INPUT_TRAY_MISSING)
- reasons[num_reasons ++] = "input-tray-missing";
- if (printer->state_reasons & _IPP_PREASON_MARKER_SUPPLY_EMPTY)
- reasons[num_reasons ++] = "marker-supply-empty-warning";
- if (printer->state_reasons & _IPP_PREASON_MARKER_SUPPLY_LOW)
- reasons[num_reasons ++] = "marker-supply-low-report";
- if (printer->state_reasons & _IPP_PREASON_MARKER_WASTE_ALMOST_FULL)
- reasons[num_reasons ++] = "marker-waste-almost-full-report";
- if (printer->state_reasons & _IPP_PREASON_MARKER_WASTE_FULL)
- reasons[num_reasons ++] = "marker-waste-full-warning";
- if (printer->state_reasons & _IPP_PREASON_MEDIA_EMPTY)
- reasons[num_reasons ++] = "media-empty-warning";
- if (printer->state_reasons & _IPP_PREASON_MEDIA_JAM)
- reasons[num_reasons ++] = "media-jam-warning";
- if (printer->state_reasons & _IPP_PREASON_MEDIA_LOW)
- reasons[num_reasons ++] = "media-low-report";
- if (printer->state_reasons & _IPP_PREASON_MEDIA_NEEDED)
- reasons[num_reasons ++] = "media-needed-report";
- if (printer->state_reasons & _IPP_PREASON_MOVING_TO_PAUSED)
- reasons[num_reasons ++] = "moving-to-paused";
- if (printer->state_reasons & _IPP_PREASON_PAUSED)
- reasons[num_reasons ++] = "paused";
- if (printer->state_reasons & _IPP_PREASON_SPOOL_AREA_FULL)
- reasons[num_reasons ++] = "spool-area-full";
- if (printer->state_reasons & _IPP_PREASON_TONER_EMPTY)
- reasons[num_reasons ++] = "toner-empty-warning";
- if (printer->state_reasons & _IPP_PREASON_TONER_LOW)
- reasons[num_reasons ++] = "toner-low-report";
-
- ippAddStrings(client->response, IPP_TAG_PRINTER,
- IPP_CONST_TAG(IPP_TAG_KEYWORD),
- "printer-state-reasons", num_reasons, NULL, reasons);
+ ipp_attribute_t *attr = NULL; /* printer-state-reasons */
+ _ipp_preason_t bit; /* Reason bit */
+ int i; /* Looping var */
+ char reason[32]; /* Reason string */
+
+ for (i = 0, bit = 1; i < (int)(sizeof(_ipp_preason_strings) / sizeof(_ipp_preason_strings[0])); i ++, bit *= 2)
+ {
+ if (printer->state_reasons & bit)
+ {
+ snprintf(reason, sizeof(reason), "%s-%s", _ipp_preason_strings[i], printer->state == IPP_PSTATE_IDLE ? "report" : printer->state == IPP_PSTATE_PROCESSING ? "warning" : "error");
+ if (attr)
+ ippSetString(client->response, &attr, ippGetCount(attr), reason);
+ else
+ attr = ippAddString(client->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "printer-state-reasons", NULL, reason);
+ }
+ }
}
}
ipp_identify_printer(
_ipp_client_t *client) /* I - Client */
{
- /* TODO: Do something */
+ ipp_attribute_t *actions, /* identify-actions */
+ *message; /* message */
+
+
+ actions = ippFindAttribute(client->request, "identify-actions", IPP_TAG_KEYWORD);
+ message = ippFindAttribute(client->request, "message", IPP_TAG_TEXT);
+
+ if (!actions || ippContainsString(actions, "sound"))
+ {
+ putchar(0x07);
+ fflush(stdout);
+ }
+
+ if (ippContainsString(actions, "display"))
+ printf("IDENTIFY from %s: %s\n", client->hostname, message ? ippGetString(message, 0, NULL) : "No message supplied");
respond_ipp(client, IPP_STATUS_OK, NULL);
}
}
+/*
+ * 'process_attr_message()' - Process an ATTR: message from a command.
+ */
+
+static void
+process_attr_message(
+ _ipp_job_t *job, /* I - Job */
+ char *message) /* I - Message */
+{
+ (void)job;
+ (void)message;
+}
+
+
/*
* 'process_client()' - Process client requests on a thread.
*/
ipp_attribute_t *attr; /* Job attribute */
char val[1280], /* IPP_NAME=value */
*valptr; /* Pointer into string */
+#ifndef WIN32
+ int mypipe[2]; /* Pipe for stderr */
+ char line[2048], /* Line from stderr */
+ *ptr, /* Pointer into line */
+ *endptr; /* End of line */
+ ssize_t bytes; /* Bytes read */
+#endif /* !WIN32 */
fprintf(stderr, "Running command \"%s %s\".\n", job->printer->command,
job->filename);
#ifdef WIN32
status = _spawnvpe(_P_WAIT, job->printer->command, myargv, myenvp);
+
#else
+ if (pipe(mypipe))
+ {
+ perror("Unable to create pipe for stderr");
+ mypipe[0] = mypipe[1] = -1;
+ }
+
if ((pid = fork()) == 0)
{
/*
* Child comes here...
*/
+ close(2);
+ dup2(mypipe[1], 2);
+ close(mypipe[0]);
+ close(mypipe[1]);
+
execve(job->printer->command, myargv, myenvp);
exit(errno);
}
perror("Unable to start job processing command");
status = -1;
+ close(mypipe[0]);
+ close(mypipe[1]);
+
/*
* Free memory used for environment...
*/
while (myenvc > 0)
free(myenvp[-- myenvc]);
+
+ /*
+ * If the pipe exists, read from it until EOF...
+ */
+
+ if (mypipe[0] >= 0)
+ {
+ close(mypipe[1]);
+
+ endptr = line;
+ while ((bytes = read(mypipe[0], endptr, sizeof(line) - (size_t)(endptr - line) - 1)) > 0)
+ {
+ endptr += bytes;
+ *endptr = '\0';
+
+ while ((ptr = strchr(line, '\n')) != NULL)
+ {
+ *ptr++ = '\0';
+
+ if (!strncmp(line, "STATE:", 6))
+ {
+ /*
+ * Process printer-state-reasons keywords.
+ */
+
+ process_state_message(job, line);
+ }
+ else if (!strncmp(line, "ATTR:", 5))
+ {
+ /*
+ * Process printer attribute update.
+ */
+
+ process_attr_message(job, line);
+ }
+ else if (Verbosity > 1)
+ fprintf(stderr, "%s: %s\n", job->printer->command, line);
+
+ bytes = ptr - line;
+ if (ptr < endptr)
+ memmove(line, ptr, (size_t)(endptr - ptr));
+ endptr -= bytes;
+ *endptr = '\0';
+ }
+ }
+
+ close(mypipe[0]);
+ }
+
/*
* Wait for child to complete...
*/
}
+/*
+ * 'process_state_message()' - Process a STATE: message from a command.
+ */
+
+static void
+process_state_message(
+ _ipp_job_t *job, /* I - Job */
+ char *message) /* I - Message */
+{
+ int i; /* Looping var */
+ _ipp_preason_t state_reasons, /* printer-state-reasons values */
+ bit; /* Current reason bit */
+ char *ptr, /* Pointer into message */
+ *next; /* Next keyword in message */
+ int remove; /* Non-zero if we are removing keywords */
+
+
+ /*
+ * Skip leading "STATE:" and any whitespace...
+ */
+
+ for (message += 6; *message; message ++)
+ if (*message != ' ' && *message != '\t')
+ break;
+
+ /*
+ * Support the following forms of message:
+ *
+ * "keyword[,keyword,...]" to set the printer-state-reasons value(s).
+ *
+ * "-keyword[,keyword,...]" to remove keywords.
+ *
+ * "+keyword[,keyword,...]" to add keywords.
+ *
+ * Keywords may or may not have a suffix (-report, -warning, -error) per
+ * RFC 2911.
+ */
+
+ if (*message == '-')
+ {
+ remove = 1;
+ state_reasons = job->printer->state_reasons;
+ message ++;
+ }
+ else if (*message == '+')
+ {
+ remove = 0;
+ state_reasons = job->printer->state_reasons;
+ message ++;
+ }
+ else
+ {
+ remove = 0;
+ state_reasons = _IPP_PREASON_NONE;
+ }
+
+ while (*message)
+ {
+ if ((next = strchr(message, ',')) != NULL)
+ *next++ = '\0';
+
+ if ((ptr = strstr(message, "-error")) != NULL)
+ *ptr = '\0';
+ else if ((ptr = strstr(message, "-report")) != NULL)
+ *ptr = '\0';
+ else if ((ptr = strstr(message, "-warning")) != NULL)
+ *ptr = '\0';
+
+ for (i = 0, bit = 1; i < (int)(sizeof(_ipp_preason_strings) / sizeof(_ipp_preason_strings[0])); i ++, bit *= 2)
+ {
+ if (!strcmp(message, _ipp_preason_strings[i]))
+ {
+ if (remove)
+ state_reasons &= ~bit;
+ else
+ state_reasons |= bit;
+ }
+ }
+
+ if (next)
+ message = next;
+ else
+ break;
+ }
+
+ job->printer->state_reasons = state_reasons;
+}
+
+
/*
* 'register_printer()' - Register a printer object via Bonjour.
*/
_ipp_client_t *client) /* I - Client */
{
int i, /* Looping var */
+ count, /* Number of values */
valid = 1; /* Valid attributes? */
ipp_attribute_t *attr, /* Current attribute */
*supported; /* xxx-supported attribute */
}
else
{
- for (i = 0;
- i < (int)(sizeof(media_supported) / sizeof(media_supported[0]));
- i ++)
- if (!strcmp(ippGetString(attr, 0, NULL), media_supported[i]))
- break;
+ supported = ippFindAttribute(client->printer->attrs, "media-supported", IPP_TAG_KEYWORD);
- if (i >= (int)(sizeof(media_supported) / sizeof(media_supported[0])))
+ if (!ippContainsString(supported, ippGetString(attr, 0, NULL)))
{
respond_unsupported(client, attr);
valid = 0;
if ((attr = ippFindAttribute(client->request, "media-col", IPP_TAG_ZERO)) != NULL)
{
+ ipp_t *col, /* media-col collection */
+ *size; /* media-size collection */
+ ipp_attribute_t *member, /* Member attribute */
+ *x_dim, /* x-dimension */
+ *y_dim; /* y-dimension */
+ int x_value, /* y-dimension value */
+ y_value; /* x-dimension value */
+
if (ippGetCount(attr) != 1 ||
ippGetValueTag(attr) != IPP_TAG_BEGIN_COLLECTION)
{
respond_unsupported(client, attr);
valid = 0;
}
- /* TODO: check for valid media-col */
+
+ col = ippGetCollection(attr, 0);
+
+ if ((member = ippFindAttribute(col, "media-size-name", IPP_TAG_ZERO)) != NULL)
+ {
+ if (ippGetCount(member) != 1 ||
+ (ippGetValueTag(member) != IPP_TAG_NAME &&
+ ippGetValueTag(member) != IPP_TAG_NAMELANG &&
+ ippGetValueTag(member) != IPP_TAG_KEYWORD))
+ {
+ respond_unsupported(client, attr);
+ valid = 0;
+ }
+ else
+ {
+ supported = ippFindAttribute(client->printer->attrs, "media-supported", IPP_TAG_KEYWORD);
+
+ if (!ippContainsString(supported, ippGetString(member, 0, NULL)))
+ {
+ respond_unsupported(client, attr);
+ valid = 0;
+ }
+ }
+ }
+ else if ((member = ippFindAttribute(col, "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL)
+ {
+ if (ippGetCount(member) != 1)
+ {
+ respond_unsupported(client, attr);
+ valid = 0;
+ }
+ else
+ {
+ size = ippGetCollection(member, 0);
+
+ if ((x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(x_dim) != 1 ||
+ (y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_INTEGER)) == NULL || ippGetCount(y_dim) != 1)
+ {
+ respond_unsupported(client, attr);
+ valid = 0;
+ }
+ else
+ {
+ x_value = ippGetInteger(x_dim, 0);
+ y_value = ippGetInteger(y_dim, 0);
+ supported = ippFindAttribute(client->printer->attrs, "media-size-supported", IPP_TAG_BEGIN_COLLECTION);
+ count = ippGetCount(supported);
+
+ for (i = 0; i < count ; i ++)
+ {
+ size = ippGetCollection(supported, i);
+ x_dim = ippFindAttribute(size, "x-dimension", IPP_TAG_ZERO);
+ y_dim = ippFindAttribute(size, "y-dimension", IPP_TAG_ZERO);
+
+ if (ippContainsInteger(x_dim, x_value) && ippContainsInteger(y_dim, y_value))
+ break;
+ }
+
+ if (i >= count)
+ {
+ respond_unsupported(client, attr);
+ valid = 0;
+ }
+ }
+ }
+ }
}
if ((attr = ippFindAttribute(client->request, "multiple-document-handling", IPP_TAG_ZERO)) != NULL)
}
else
{
- int count, /* Number of supported values */
- xdpi, /* Horizontal resolution for job template attribute */
+ int xdpi, /* Horizontal resolution for job template attribute */
ydpi, /* Vertical resolution for job template attribute */
sydpi; /* Vertical resolution for supported value */
ipp_res_t units, /* Units for job template attribute */
return (valid);
}
-
-
-/*
- * End of "$Id$".
- */