CHANGES-1.3.txt
---------------
+CHANGES IN CUPS V1.3.9
+
+ - ppdEmit*() did not support custom JCL options (STR #2889)
+ - The cupstestppd utility incorrectly reported missing
+ "en" base translations (STR #2887)
+
+
CHANGES IN CUPS V1.3.8
- Documentation updates (STR #2785, STR #2861, STR #2862)
+ - The scheduler did not add the ending job sheet when the
+ job was released.
- The IPP backend did not relay marker-* attributes.
- The CUPS GNOME/KDE menu item was not localized for
Chinese (STR #2880)
-CHANGES.txt - 2008-07-18
+CHANGES.txt - 2008-07-23
------------------------
CHANGES IN CUPS V1.4b1
+ - Added ppdPageSizeLimits API.
+ - Added support for new cupsMediaQualifier2, cupsMediaQualifier3,
+ cupsMinSize, and cupsMaxSize attributes.
+ - Added cupsResolveConflicts and ppdInstallableConflict APIs.
- Added support for new cupsUIConstraints and cupsUIResolver
attributes for better option conflict detection and
resolution.
if (!g.make || !g.model)
{
- _cupsLangPrintf(stderr,
- _("ERROR: Unable to create make and model strings\n"));
- return CUPS_BACKEND_STOP;
+ _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+
+ if (!g.make)
+ fputs("DEBUG: USB make string is NULL!\n", stderr);
+ if (!g.model)
+ fputs("DEBUG: USB model string is NULL!\n", stderr);
+
+ return (CUPS_BACKEND_STOP);
}
fputs("STATE: +connecting-to-device\n", stderr);
strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
- _cupsLangPrintf(stderr, _("FATAL: Could not load %s\n"), print_buffer);
+ _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+ fprintf(stderr, "DEBUG: Could not load %s\n", print_buffer);
if (driverBundlePath)
CFRelease(driverBundlePath);
- return CUPS_BACKEND_STOP;
+ return (CUPS_BACKEND_STOP);
}
if (driverBundlePath)
countdown -= PRINTER_POLLING_INTERVAL;
if (countdown <= 0)
{
- _cupsLangPrintf(stderr, _("INFO: Printer busy (status:0x%08x)\n"),
- (int)status);
+ _cupsLangPuts(stderr,
+ _("INFO: Waiting for printer to become available...\n"));
+ fprintf(stderr, "DEBUG: USB printer status: 0x%08x\n", (int)status);
countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 15 seconds */
}
}
if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
{
- _cupsLangPuts(stderr, _("WARNING: Couldn't create side channel\n"));
- return CUPS_BACKEND_STOP;
+ _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+ fputs("DEBUG: Couldn't create side-channel thread!\n", stderr);
+ return (CUPS_BACKEND_STOP);
}
}
if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
{
- _cupsLangPuts(stderr, _("WARNING: Couldn't create read channel\n"));
- return CUPS_BACKEND_STOP;
+ _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+ fputs("DEBUG: Couldn't create read thread!\n", stderr);
+ return (CUPS_BACKEND_STOP);
}
/*
while (status == noErr && copies-- > 0)
{
- _cupsLangPuts(stderr, _("INFO: Sending data\n"));
+ _cupsLangPuts(stderr, _("INFO: Sending print data...\n"));
if (print_fd != STDIN_FILENO)
{
}
else if (errno != EAGAIN)
{
- _cupsLangPrintf(stderr, _("ERROR: select() returned %d\n"), (int)errno);
- return CUPS_BACKEND_STOP;
+ _cupsLangPuts(stderr, _("ERROR: Unable to read print data!\n"));
+ perror("DEBUG: select");
+ return (CUPS_BACKEND_STOP);
}
}
if (errno != EAGAIN || errno != EINTR)
{
- _cupsLangPrintError(_("ERROR: Unable to read print data"));
+ _cupsLangPuts(stderr, _("ERROR: Unable to read print data!\n"));
+ perror("DEBUG: read");
return CUPS_BACKEND_STOP;
}
*/
OSStatus err = (*g.classdriver)->Abort(g.classdriver);
- _cupsLangPrintf(stderr, _("ERROR: %ld: (canceled:%ld)\n"),
- (long)status, (long)err);
+ _cupsLangPuts(stderr, _("ERROR: Unable to send print data!\n"));
+ fprintf(stderr, "DEBUG: USB class driver WritePipe returned %ld\n",
+ (long)status);
+ fprintf(stderr, "DEBUG: USB class driver Abort returned %ld\n",
+ (long)err);
status = CUPS_BACKEND_STOP;
break;
}
langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
CFPreferencesSetAppValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication);
- fprintf(stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang);
+ fprintf(stderr, "DEBUG: usb: AppleLanguages=\"%s\"\n", requestedLang);
CFRelease(lang[0]);
CFRelease(langArray);
execv("/usr/libexec/cups/backend/usb", my_argv);
- _cupsLangPrintError(_("ERROR: Unable to exec /usr/libexec/cups/backend/usb"));
+ _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
+ perror("DEBUG: Unable to exec /usr/libexec/cups/backend/usb");
exit(errno);
}
else if (child_pid < 0)
* Error - couldn't fork a new process!
*/
- _cupsLangPrintError(_("ERROR: Unable to fork"));
+ _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
+ perror("DEBUG: Unable to fork");
exit(errno);
}
close(fd);
close(1);
- fprintf(stderr, "DEBUG: Started usb(ppc) backend (PID %d)\n", (int)child_pid);
+ fprintf(stderr, "DEBUG: Started usb(legacy) backend (PID %d)\n",
+ (int)child_pid);
while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
usleep(1000);
if (WIFSIGNALED(childstatus))
{
exitstatus = WTERMSIG(childstatus);
- fprintf(stderr, "DEBUG: usb(ppc) backend %d crashed on signal %d!\n", child_pid, exitstatus);
+ fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d!\n",
+ child_pid, exitstatus);
}
else
{
if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
- fprintf(stderr, "DEBUG: usb(ppc) backend %d stopped with status %d!\n", child_pid, exitstatus);
+ fprintf(stderr,
+ "DEBUG: usb(legacy) backend %d stopped with status %d!\n",
+ child_pid, exitstatus);
else
- fprintf(stderr, "DEBUG: PID %d exited with no errors\n", child_pid);
+ fprintf(stderr, "DEBUG: usb(legacy) backend %d exited with no errors\n",
+ child_pid);
}
}
else
{
- fputs("DEBUG: usb child running i386 again\n", stderr);
+ fputs("DEBUG: usb(legacy) backend running native again\n", stderr);
exitstatus = ENOENT;
}
*
* Contents:
*
+ * list_devices() - List the available printers.
+ * print_device() - Print a file to a USB device.
+ * close_device() - Close the connection to the USB printer.
+ * find_device() - Find or enumerate USB printers.
+ * get_device_id() - Get the IEEE-1284 device ID for the printer.
+ * list_cb() - List USB printers for discovery.
+ * make_device_uri() - Create a device URI for a USB printer.
+ * open_device() - Open a connection to the USB printer.
+ * print_cb() - Find a USB printer for printing.
+ * side_cb() - Handle side-channel requests.
*/
/*
*/
#include <usb.h>
+#include <poll.h>
/*
static int open_device(usb_printer_t *printer, int verbose);
static int print_cb(usb_printer_t *printer, const char *device_uri,
const char *device_id, const void *data);
+static ssize_t side_cb(usb_printer_t *printer, int print_fd);
/*
tbytes; /* Total bytes written */
char buffer[8192]; /* Print data buffer */
struct sigaction action; /* Actions for POSIX signals */
- int read_endp, /* Read endpoint */
- write_endp; /* Write endpoint */
+ struct pollfd pfds[2]; /* Poll descriptors */
fputs("DEBUG: print_device\n", stderr);
sleep(5);
}
- read_endp = printer->device->config[printer->conf].
- interface[printer->iface].
- altsetting[printer->altset].
- endpoint[printer->read_endp].bEndpointAddress;
- write_endp = printer->device->config[printer->conf].
- interface[printer->iface].
- altsetting[printer->altset].
- endpoint[printer->write_endp].bEndpointAddress;
/*
* If we are printing data from a print driver on stdin, ignore SIGTERM
tbytes = 0;
+ pfds[0].fd = print_fd;
+ pfds[0].events = POLLIN;
+ pfds[1].fd = CUPS_SC_FD;
+ pfds[1].events = POLLIN;
+
while (copies > 0 && tbytes >= 0)
{
copies --;
}
/*
- * TODO: Add side-channel and back-channel support, along with better
- * error handling for writes.
+ * TODO: Add back-channel support, along with better write error handling.
*/
- while ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+ if (poll(pfds, 2, -1) > 0)
{
- while (usb_bulk_write(printer->handle, write_endp, buffer, bytes,
- 5000) < 0)
+ if (pfds[0].revents & POLLIN)
{
- _cupsLangPrintf(stderr,
- _("ERROR: Unable to write %d bytes to printer!\n"),
- (int)bytes);
- tbytes = -1;
- break;
+ if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+ {
+ while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
+ bytes, 5000) < 0)
+ {
+ _cupsLangPrintf(stderr,
+ _("ERROR: Unable to write %d bytes to printer!\n"),
+ (int)bytes);
+ tbytes = -1;
+ break;
+ }
+
+ tbytes += bytes;
+ }
+ else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
+ break;
}
- tbytes += bytes;
+ if (pfds[1].revents & POLLIN)
+ tbytes += side_cb(printer, print_fd);
}
}
sizeof(device_uri));
if ((*cb)(&printer, device_uri, device_id, data))
+ {
+ printer.read_endp = printer.device->config[printer.conf].
+ interface[printer.iface].
+ altsetting[printer.altset].
+ endpoint[printer.read_endp].
+ bEndpointAddress;
+ printer.write_endp = printer.device->config[printer.conf].
+ interface[printer.iface].
+ altsetting[printer.altset].
+ endpoint[printer.write_endp].
+ bEndpointAddress;
return (&printer);
+ }
}
close_device(&printer);
}
+/*
+ * 'side_cb()' - Handle side-channel requests.
+ */
+
+static ssize_t /* O - Number of bytes written */
+side_cb(usb_printer_t *printer, /* I - Printer */
+ int print_fd) /* I - File to print */
+{
+ ssize_t bytes, /* Bytes read/written */
+ tbytes; /* Total bytes written */
+ char buffer[8192]; /* Print data buffer */
+ struct pollfd pfd; /* Poll descriptor */
+ cups_sc_command_t command; /* Request command */
+ cups_sc_status_t status; /* Request/response status */
+ char data[2048]; /* Request/response data */
+ int datalen; /* Request/response data size */
+
+
+ tbytes = 0;
+ datalen = sizeof(data);
+
+ if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+ {
+ _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n"));
+ return (0);
+ }
+
+ switch (command)
+ {
+ case CUPS_SC_CMD_DRAIN_OUTPUT :
+ pfd.fd = print_fd;
+ pfd.events = POLLIN;
+
+ while (poll(&pfd, 1, 1000) > 0)
+ {
+ if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+ {
+ while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
+ bytes, 5000) < 0)
+ {
+ _cupsLangPrintf(stderr,
+ _("ERROR: Unable to write %d bytes to printer!\n"),
+ (int)bytes);
+ tbytes = -1;
+ break;
+ }
+
+ tbytes += bytes;
+ }
+ else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
+ break;
+ }
+
+ if (tbytes < 0)
+ status = CUPS_SC_STATUS_IO_ERROR;
+ else
+ status = CUPS_SC_STATUS_OK;
+
+ datalen = 0;
+ break;
+
+ case CUPS_SC_CMD_GET_BIDI :
+ data[0] = 0; /* TODO: Change to 1 when read supported */
+ datalen = 1;
+ break;
+
+ case CUPS_SC_CMD_GET_DEVICE_ID :
+ if (get_device_id(printer, data, sizeof(data)))
+ {
+ status = CUPS_SC_STATUS_IO_ERROR;
+ datalen = 0;
+ }
+ else
+ {
+ status = CUPS_SC_STATUS_OK;
+ datalen = strlen(data);
+ }
+ break;
+
+ default :
+ status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+ datalen = 0;
+ break;
+ }
+
+ cupsSideChannelWrite(command, status, data, datalen, 1.0);
+
+ return (tbytes);
+}
+
+
/*
* End of "$Id$".
*/
options.o: cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
options.o: string.h ../config.h debug.h
page.o: ppd.h array.h versioning.h file.h string.h ../config.h
-ppd.o: globals.h string.h ../config.h http-private.h http.h versioning.h
-ppd.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
-ppd.o: i18n.h transcode.h debug.h
+ppd.o: ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h file.h
+ppd.o: language.h globals.h string.h ../config.h http-private.h md5.h
+ppd.o: ipp-private.h i18n.h transcode.h debug.h
request.o: globals.h string.h ../config.h http-private.h http.h versioning.h
request.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
request.o: i18n.h transcode.h debug.h
options.32.o: options.c cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
options.32.o: options.c string.h ../config.h debug.h
page.32.o: page.c ppd.h array.h versioning.h file.h string.h ../config.h
-ppd.32.o: ppd.c globals.h string.h ../config.h http-private.h http.h versioning.h
-ppd.32.o: ppd.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
-ppd.32.o: ppd.c i18n.h transcode.h debug.h
+ppd.32.o: ppd.c ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h file.h
+ppd.32.o: ppd.c language.h globals.h string.h ../config.h http-private.h md5.h
+ppd.32.o: ppd.c ipp-private.h i18n.h transcode.h debug.h
request.32.o: request.c globals.h string.h ../config.h http-private.h http.h versioning.h
request.32.o: request.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
request.32.o: request.c i18n.h transcode.h debug.h
options.64.o: options.c cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
options.64.o: options.c string.h ../config.h debug.h
page.64.o: page.c ppd.h array.h versioning.h file.h string.h ../config.h
-ppd.64.o: ppd.c globals.h string.h ../config.h http-private.h http.h versioning.h
-ppd.64.o: ppd.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
-ppd.64.o: ppd.c i18n.h transcode.h debug.h
+ppd.64.o: ppd.c ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h file.h
+ppd.64.o: ppd.c language.h globals.h string.h ../config.h http-private.h md5.h
+ppd.64.o: ppd.c ipp-private.h i18n.h transcode.h debug.h
request.64.o: request.c globals.h string.h ../config.h http-private.h http.h versioning.h
request.64.o: request.c md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
request.64.o: request.c i18n.h transcode.h debug.h
for (i = 0; i < *num_options; i ++)
num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value,
num_newopts, &newopts);
- if (option)
+ if (option && strcasecmp(option, "Collate"))
num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
/*
}
/*
- * Free either the old or the new options depending on whether we had to
- * apply any resolvers...
+ * Free the caller's option array...
*/
- if (resolvers)
- {
- cupsFreeOptions(*num_options, *options);
- *num_options = num_newopts;
- *options = newopts;
- }
+ cupsFreeOptions(*num_options, *options);
+
+ /*
+ * If Collate is the option we are testing, add it here. Otherwise, remove
+ * any Collate option from the resolve list since the filters automatically
+ * handle manual collation...
+ */
+
+ if (option && !strcasecmp(option, "Collate"))
+ num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
else
- cupsFreeOptions(num_newopts, newopts);
+ num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
+
+ /*
+ * Return the new list of options to the caller...
+ */
+
+ *num_options = num_newopts;
+ *options = newopts;
cupsArrayDelete(pass);
cupsArrayDelete(resolvers);
for (i = 0, vptr = strchr(constattr->value, '*');
vptr;
- i ++, vptr = strchr(vptr + 1, '*'), constptr ++)
+ i ++, vptr = strchr(vptr, '*'), constptr ++)
{
/*
* Extract "*Option Choice" or just "*Option"...
vptr ++;
if (*vptr == '*')
- {
- vptr --;
choice[0] = '\0';
- }
else
{
for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
constptr->installable = ppd_is_installable(installable, option);
consts->installable |= constptr->installable;
- if (!constptr->option)
+ if (!constptr->option || (!constptr->choice && choice[0]))
{
- DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n", option));
+ DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
+ option, choice));
break;
}
}
oldconst->option1);
}
- if (!constptr[0].option)
+ if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
{
- DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
- oldconst->option1));
+ DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
+ oldconst->option1, oldconst->choice1));
free(consts->constraints);
free(consts);
continue;
oldconst->option2);
}
- if (!constptr->option)
+ if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
{
- DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
- oldconst->option2));
+ DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
+ oldconst->option2, oldconst->choice2));
free(consts->constraints);
free(consts);
continue;
for (i = 0, bufsize = 1; i < count; i ++)
{
- if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
+ if (section == PPD_ORDER_JCL)
+ {
+ if (!strcasecmp(choices[i]->choice, "Custom") &&
+ (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
+ != NULL)
+ {
+ /*
+ * Add space to account for custom parameter substitution...
+ */
+
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_POINTS :
+ case PPD_CUSTOM_REAL :
+ case PPD_CUSTOM_INT :
+ bufsize += 10;
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ bufsize += strlen(cparam->current.custom_string);
+ break;
+ }
+ }
+ }
+ }
+ else if (section != PPD_ORDER_EXIT)
{
bufsize += 3; /* [{\n */
*/
for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr))
- if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
+ if (section == PPD_ORDER_JCL)
+ {
+ if (!strcasecmp(choices[i]->choice, "Custom") &&
+ (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
+ != NULL)
+ {
+ /*
+ * Handle substitutions in custom JCL options...
+ */
+
+ char *cptr; /* Pointer into code */
+ int pnum; /* Parameter number */
+
+
+ for (cptr = choices[i]->code; *cptr && bufptr < bufend;)
+ {
+ if (*cptr == '\\')
+ {
+ cptr ++;
+
+ if (isdigit(*cptr & 255))
+ {
+ /*
+ * Substitute parameter...
+ */
+
+ pnum = *cptr++ - '0';
+ while (isalnum(*cptr & 255))
+ pnum = pnum * 10 + *cptr - '0';
+
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ if (cparam->order == pnum)
+ break;
+
+ if (cparam)
+ {
+ switch (cparam->type)
+ {
+ case PPD_CUSTOM_CURVE :
+ case PPD_CUSTOM_INVCURVE :
+ case PPD_CUSTOM_POINTS :
+ case PPD_CUSTOM_REAL :
+ bufptr = _cupsStrFormatd(bufptr, bufend,
+ cparam->current.custom_real,
+ loc);
+ break;
+
+ case PPD_CUSTOM_INT :
+ snprintf(bufptr, bufend - bufptr, "%d",
+ cparam->current.custom_int);
+ bufptr += strlen(bufptr);
+ break;
+
+ case PPD_CUSTOM_PASSCODE :
+ case PPD_CUSTOM_PASSWORD :
+ case PPD_CUSTOM_STRING :
+ strlcpy(bufptr, cparam->current.custom_string,
+ bufend - bufptr);
+ bufptr += strlen(bufptr);
+ break;
+ }
+ }
+ }
+ else if (*cptr)
+ *bufptr++ = *cptr++;
+ }
+ else
+ *bufptr++ = *cptr++;
+ }
+ }
+ else
+ {
+ /*
+ * Otherwise just copy the option code directly...
+ */
+
+ strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
+ bufptr += strlen(bufptr);
+ }
+ }
+ else if (section != PPD_ORDER_EXIT)
{
/*
* Add wrapper commands to prevent printer errors for unsupported
}
}
else if (!strcasecmp(choices[i]->choice, "Custom") &&
- (coption = ppdFindCustomOption(ppd,
- choices[i]->option->keyword))
+ (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
!= NULL)
{
/*
_ppdOpenFile
_ppdPageLength
_ppdPageSize
+_ppdPageSizeLimits
_ppdPageWidth
_ppdSetConformance
}
+/*
+ * 'ppdPageSizeLimits()' - Return the custom page size limits.
+ *
+ * This function returns the minimum and maximum custom page sizes and printable
+ * areas based on the currently-marked (selected) options.
+ *
+ * If the specified PPD file does not support custom page sizes, both
+ * "minimum" and "maximum" are filled with zeroes.
+ *
+ * @since CUPS 1.4@
+ */
+
+int /* O - 1 if custom sizes are supported, 0 otherwise */
+ppdPageSizeLimits(ppd_file_t *ppd, /* I - PPD file record */
+ ppd_size_t *minimum, /* O - Minimum custom size */
+ ppd_size_t *maximum) /* O - Maximum custom size */
+{
+ ppd_choice_t *qualifier2, /* Second media qualifier */
+ *qualifier3; /* Third media qualifier */
+ ppd_attr_t *attr; /* Attribute */
+ float width, /* Min/max width */
+ length; /* Min/max length */
+ char spec[PPD_MAX_NAME]; /* Selector for min/max */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !ppd->variable_sizes || !minimum || !maximum)
+ {
+ if (minimum)
+ memset(minimum, 0, sizeof(ppd_size_t));
+
+ if (maximum)
+ memset(maximum, 0, sizeof(ppd_size_t));
+
+ return (0);
+ }
+
+ /*
+ * See if we have the cupsMediaQualifier2 and cupsMediaQualifier3 attributes...
+ */
+
+ cupsArraySave(ppd->sorted_attrs);
+
+ if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier2", NULL)) != NULL &&
+ attr->value)
+ qualifier2 = ppdFindMarkedChoice(ppd, attr->value);
+ else
+ qualifier2 = NULL;
+
+ if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier3", NULL)) != NULL &&
+ attr->value)
+ qualifier3 = ppdFindMarkedChoice(ppd, attr->value);
+ else
+ qualifier3 = NULL;
+
+ /*
+ * Figure out the current minimum width and length...
+ */
+
+ if (qualifier2)
+ {
+ /*
+ * Try getting cupsMinSize...
+ */
+
+ if (qualifier3)
+ {
+ snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
+ qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+ }
+ else
+ attr = NULL;
+
+ if (!attr)
+ {
+ snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
+ attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+ }
+
+ if (!attr && qualifier3)
+ {
+ snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+ }
+
+ if (!attr ||
+ (attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2))
+ {
+ width = ppd->custom_min[0];
+ length = ppd->custom_min[1];
+ }
+ }
+ else
+ {
+ width = ppd->custom_min[0];
+ length = ppd->custom_min[1];
+ }
+
+ minimum->width = width;
+ minimum->length = length;
+ minimum->left = ppd->custom_margins[0];
+ minimum->bottom = ppd->custom_margins[1];
+ minimum->right = width - ppd->custom_margins[2];
+ minimum->top = length - ppd->custom_margins[3];
+
+ /*
+ * Figure out the current maximum width and length...
+ */
+
+ if (qualifier2)
+ {
+ /*
+ * Try getting cupsMaxSize...
+ */
+
+ if (qualifier3)
+ {
+ snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
+ qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+ }
+ else
+ attr = NULL;
+
+ if (!attr)
+ {
+ snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
+ attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+ }
+
+ if (!attr && qualifier3)
+ {
+ snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
+ attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+ }
+
+ if (!attr ||
+ (attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2))
+ {
+ width = ppd->custom_max[0];
+ length = ppd->custom_max[1];
+ }
+ }
+ else
+ {
+ width = ppd->custom_max[0];
+ length = ppd->custom_max[1];
+ }
+
+ maximum->width = width;
+ maximum->length = length;
+ maximum->left = ppd->custom_margins[0];
+ maximum->bottom = ppd->custom_margins[1];
+ maximum->right = width - ppd->custom_margins[2];
+ maximum->top = length - ppd->custom_margins[3];
+
+ /*
+ * Return the min and max...
+ */
+
+ cupsArrayRestore(ppd->sorted_attrs);
+
+ return (1);
+}
+
+
/*
* 'ppdPageWidth()' - Get the page width for the given size.
*/
* Include necessary headers.
*/
+#include "ppd-private.h"
#include "globals.h"
#include "debug.h"
#include <stdlib.h>
cupsArrayDelete(ppd->coptions);
+ /*
+ * Free constraints...
+ */
+
+ if (ppd->cups_uiconstraints)
+ {
+ _ppd_cups_uiconsts_t *consts; /* Current constraints */
+
+
+ for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
+ consts;
+ consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
+ {
+ free(consts->constraints);
+ free(consts);
+ }
+
+ cupsArrayDelete(ppd->cups_uiconstraints);
+ }
+
/*
* Free the whole record...
*/
sizeof(choice->text));
choice->code = _cupsStrAlloc(string);
+
+ if (custom_option->section == PPD_ORDER_JCL)
+ ppd_decode(choice->code);
}
/*
const char *spec);
extern const char *ppdLocalizeMarkerName(ppd_file_t *ppd,
const char *name) _CUPS_API_1_4;
+extern int ppdPageSizeLimits(ppd_file_t *ppd,
+ ppd_size_t *minimum,
+ ppd_size_t *maximum) _CUPS_API_1_4;
/*
*ParamCustomPageSize HeightOffset/Height Offset: 4 points 0 0
*ParamCustomPageSize Orientation: 5 int 0 0
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+
*OpenUI *InputSlot/Input Slot: PickOne
*OrderDependency: 20 AnySetup *InputSlot
*DefaultInputSlot: Tray
const char *text; /* Localized text */
int num_options; /* Number of options */
cups_option_t *options; /* Options */
+ ppd_size_t minsize, /* Minimum size */
+ maxsize; /* Maximum size */
status = 0;
status ++;
}
+ /*
+ * ppdPageSizeLimits
+ */
+
+ fputs("ppdPageSizeLimits: ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 36 || minsize.length != 36 ||
+ maxsize.width != 1080 || maxsize.length != 86400)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=36x36, max=1080x86400)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
/*
* Test localization...
*/
puts("FAIL (Duplex=None conflicted)");
status ++;
}
+
+ /*
+ * ppdPageSizeLimits
+ */
+
+ ppdMarkDefaults(ppd);
+
+ fputs("ppdPageSizeLimits(default): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 36 || minsize.length != 36 ||
+ maxsize.width != 1080 || maxsize.length != 86400)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=36x36, max=1080x86400)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
+ ppdMarkOption(ppd, "InputSlot", "Manual");
+
+ fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 100 || minsize.length != 100 ||
+ maxsize.width != 1000 || maxsize.length != 1000)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=100x100, max=1000x1000)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
+ ppdMarkOption(ppd, "Quality", "Photo");
+
+ fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 200 || minsize.length != 200 ||
+ maxsize.width != 1000 || maxsize.length != 1000)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=200x200, max=1000x1000)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
+
+ ppdMarkOption(ppd, "InputSlot", "Tray");
+
+ fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
+ if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+ {
+ if (minsize.width != 300 || minsize.length != 300 ||
+ maxsize.width != 1080 || maxsize.length != 86400)
+ {
+ printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+ "expected min=300x300, max=1080x86400)\n", minsize.width,
+ minsize.length, maxsize.width, maxsize.length);
+ status ++;
+ }
+ else
+ puts("PASS");
+ }
+ else
+ {
+ puts("FAIL (returned 0)");
+ status ++;
+ }
}
else
{
<li><a href="#ppdOpenFile" title="Read a PPD file into memory.">ppdOpenFile</a></li>
<li><a href="#ppdPageLength" title="Get the page length for the given size.">ppdPageLength</a></li>
<li><a href="#ppdPageSize" title="Get the page size record for the given size.">ppdPageSize</a></li>
+<li><a href="#ppdPageSizeLimits" title="Return the custom page size limits.">ppdPageSizeLimits</a></li>
<li><a href="#ppdPageWidth" title="Get the page width for the given size.">ppdPageWidth</a></li>
<li><a href="#ppdSetConformance" title="Set the conformance level for PPD files.">ppdSetConformance</a></li>
</ul>
</dl>
<h4 class="returnvalue">Return Value</h4>
<p class="description">Size record for page or NULL</p>
+<h3 class="function"><span class="info"> CUPS 1.4 </span><a name="ppdPageSizeLimits">ppdPageSizeLimits</a></h3>
+<p class="description">Return the custom page size limits.</p>
+<p class="code">
+int ppdPageSizeLimits (<br>
+ <a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+ <a href="#ppd_size_t">ppd_size_t</a> *minimum,<br>
+ <a href="#ppd_size_t">ppd_size_t</a> *maximum<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>minimum</dt>
+<dd class="description">Minimum custom size</dd>
+<dt>maximum</dt>
+<dd class="description">Maximum custom size</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if custom sizes are supported, 0 otherwise</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the minimum and maximum custom page sizes and printable
+areas based on the currently-marked (selected) options.<br>
+<br>
+If the specified PPD file does not support custom page sizes, both
+"minimum" and "maximum" are filled with zeroes.
+
+</p>
<h3 class="function"><a name="ppdPageWidth">ppdPageWidth</a></h3>
<p class="description">Get the page width for the given size.</p>
<p class="code">
cupsdLogJob(job, CUPSD_LOG_INFO, "Released by \"%s\".", username);
con->response->request.status.status_code = IPP_OK;
+
+ cupsdCheckJobs();
}
/* Resource portion of URI */
int port; /* Port portion of URI */
int event; /* Events? */
+ int check_jobs; /* Check jobs? */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con,
cupsdLoadJob(job);
- event = 0;
+ check_jobs = 0;
+ event = 0;
for (attr = con->request->attrs; attr; attr = attr->next)
{
}
else if (con->response->request.status.status_code == IPP_OK)
{
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-priority to %d",
+ attr->values[0].integer);
cupsdSetJobPriority(job, attr->values[0].integer);
- event |= CUPSD_EVENT_JOB_CONFIG_CHANGED |
- CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED;
+
+ check_jobs = 1;
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED |
+ CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED;
}
}
else if (!strcmp(attr->name, "job-state"))
}
else if (con->response->request.status.status_code == IPP_OK)
{
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
+ attr->values[0].integer);
+
job->state->values[0].integer = attr->values[0].integer;
job->state_value = (ipp_jstate_t)attr->values[0].integer;
event |= CUPSD_EVENT_JOB_STATE;
+ check_jobs = 1;
}
break;
return;
}
else if (con->response->request.status.status_code == IPP_OK)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
+ attr->values[0].integer);
cupsdCancelJob(job, 0, (ipp_jstate_t)attr->values[0].integer);
+
+ check_jobs = 1;
+ }
break;
}
}
if (!strcmp(attr->name, "job-hold-until"))
{
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s",
+ attr->values[0].string.text);
cupsdSetJobHoldUntil(job, attr->values[0].string.text);
if (!strcmp(attr->values[0].string.text, "no-hold"))
else
cupsdHoldJob(job);
- event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
+ check_jobs = 1;
+ event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
}
}
else if (attr->value_tag == IPP_TAG_DELETEATTR)
* Start jobs if possible...
*/
- cupsdCheckJobs();
+ if (check_jobs)
+ cupsdCheckJobs();
}
*/
cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdCheckJobs: Job %d: state_value=%d, loaded=%s",
- job->id, job->state_value, job->attrs ? "yes" : "no");
+ "cupsdCheckJobs: Job %d: dest=%s, dtype=%x, "
+ "state_value=%d, loaded=%s", job->id, job->dest, job->dtype,
+ job->state_value, job->attrs ? "yes" : "no");
if (job->state_value == IPP_JOB_HELD &&
job->hold_until &&
job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
-
- cupsdCheckJobs();
}
if (job->state_value == IPP_JOB_HELD)
{
+ /*
+ * Add trailing banner as needed...
+ */
+
+ if (job->pending_timeout)
+ cupsdTimeoutJob(job);
+
DEBUG_puts("cupsdReleaseJob: setting state to pending...");
job->state->values[0].integer = IPP_JOB_PENDING;
job->state_value = IPP_JOB_PENDING;
job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
- cupsdCheckJobs();
}
}
if (old_state > IPP_JOB_STOPPED)
cupsArrayAdd(ActiveJobs, job);
-
- cupsdCheckJobs();
}
}
*/
static int check_log_file(cups_file_t **lf, const char *logname);
-static char *format_log_line(const char *message, va_list ap);
+static int format_log_line(const char *message, va_list ap);
/*
...) /* I - Additional arguments as needed */
{
va_list ap; /* Argument pointer */
- char jobmsg[1024], /* Format string for job message */
- *line; /* Message line */
+ char jobmsg[1024]; /* Format string for job message */
+ int status; /* Formatting status */
/*
snprintf(jobmsg, sizeof(jobmsg), "[Job %d] %s", job->id, message);
- va_start(ap, message);
- line = format_log_line(jobmsg, ap);
- va_end(ap);
+ do
+ {
+ va_start(ap, message);
+ status = format_log_line(jobmsg, ap);
+ va_end(ap);
+ }
+ while (status == 0);
- if (line)
- return (cupsdWriteErrorLog(level, line));
+ if (status > 0)
+ return (cupsdWriteErrorLog(level, log_line));
else
return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
"Unable to allocate memory for log line!"));
...) /* I - Additional args as needed */
{
va_list ap; /* Argument pointer */
- char *line; /* Message line */
+ int status; /* Formatting status */
/*
* Format and write the log message...
*/
- va_start(ap, message);
- line = format_log_line(message, ap);
- va_end(ap);
+ do
+ {
+ va_start(ap, message);
+ status = format_log_line(message, ap);
+ va_end(ap);
+ }
+ while (status == 0);
- if (line)
- return (cupsdWriteErrorLog(level, line));
+ if (status > 0)
+ return (cupsdWriteErrorLog(level, log_line));
else
return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
"Unable to allocate memory for log line!"));
* to format_log_line()...
*/
-static char * /* O - Text or NULL on error */
+static int /* O - -1 for fatal, 0 for retry, 1 for success */
format_log_line(const char *message, /* I - Printf-style format string */
va_list ap) /* I - Argument list */
{
- int len; /* Length of formatted line */
+ int len; /* Length of formatted line */
/*
log_line = malloc(log_linesize);
if (!log_line)
- return (NULL);
+ return (-1);
}
/*
{
log_line = temp;
log_linesize = len;
- }
- vsnprintf(log_line, log_linesize, message, ap);
+ return (0);
+ }
}
- return (log_line);
+ return (1);
}
if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
duplex = ppdFindOption(ppd, "JCLDuplex");
- if (duplex && duplex->num_choices > 1)
+ if (duplex && duplex->num_choices > 1 &&
+ !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
{
p->type |= CUPS_PRINTER_DUPLEX;
for (vptr = strchr(constattr->value, '*');
vptr;
- vptr = strchr(vptr + 1, '*'))
+ vptr = strchr(vptr, '*'))
{
/*
* Extract "*Option Choice" or just "*Option"...
vptr ++;
if (*vptr == '*')
- {
- vptr --;
choice[0] = '\0';
- }
else
{
for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
strlcpy(ll, language, sizeof(ll));
- if (!cupsArrayFind(languages, ll) && strcmp(ll, "zh"))
+ if (!cupsArrayFind(languages, ll) &&
+ strcmp(ll, "zh") && strcmp(ll, "en"))
{
if (!warn && !errors && !verbose)
_cupsLangPuts(stdout, _(" FAIL\n"));
tar cjf cups-$fileversion-source.tar.bz2 cups-$version
echo "..."
+if test -x /usr/bin/md5sum; then
+ (cd /tmp; md5sum cups-$fileversion-source.tar.* | awk '{print $1, "'$fileversion' cups/'$fileversion'/" $2}')
+elif test -x /sbin/md5; then
+ (cd /tmp; md5 cups-$fileversion-source.tar.* | awk '{print $4, "'$fileversion' cups/'$fileversion'/" substr($2, 2, length($2) - 2)}')
+fi
+
echo Removing temporary files...
rm -rf cups-$version