|
|
|
|
/*
|
|
|
|
|
* USB printer backend for CUPS.
|
|
|
|
|
*
|
|
|
|
|
* Copyright © 2007-2012 by Apple Inc.
|
|
|
|
|
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|
|
|
|
* information.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Include necessary headers.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
/* A header order dependency requires this be first */
|
|
|
|
|
# include <ApplicationServices/ApplicationServices.h>
|
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
|
|
|
|
|
|
#include "backend-private.h"
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
# include <io.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
# include <fcntl.h>
|
|
|
|
|
# include <termios.h>
|
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Local functions...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void list_devices(void);
|
|
|
|
|
int print_device(const char *uri, const char *hostname,
|
|
|
|
|
const char *resource, char *options,
|
|
|
|
|
int print_fd, int copies, int argc, char *argv[]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Include the vendor-specific USB implementation...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBUSB
|
|
|
|
|
# include "usb-libusb.c"
|
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
|
# include "usb-darwin.c"
|
|
|
|
|
#elif defined(__linux) || defined(__sun) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
|
|
|
|
|
# include "usb-unix.c"
|
|
|
|
|
#else
|
|
|
|
|
/*
|
|
|
|
|
* Use dummy functions that do nothing on unsupported platforms...
|
|
|
|
|
* These can be used as templates for implementing USB printing on new
|
|
|
|
|
* platforms...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 'list_devices()' - List all available USB devices to stdout.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
list_devices(void)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Don't have any devices to list... Use output of the form:
|
|
|
|
|
*
|
|
|
|
|
* direct usb:/make/model?serial=foo "Make Model" "USB Printer"
|
|
|
|
|
*
|
|
|
|
|
* Note that "Hewlett Packard" or any other variation MUST be mapped to
|
|
|
|
|
* "HP" for compatibility with the PPD and ICC specs.
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 'print_device()' - Print a file to a USB device.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int /* O - Exit status */
|
|
|
|
|
print_device(const char *uri, /* I - Device URI */
|
|
|
|
|
const char *hostname, /* I - Hostname/manufacturer */
|
|
|
|
|
const char *resource, /* I - Resource/modelname */
|
|
|
|
|
char *options, /* I - Device options/serial number */
|
|
|
|
|
int print_fd, /* I - File descriptor to print */
|
|
|
|
|
int copies, /* I - Copies to print */
|
|
|
|
|
int argc, /* I - Number of command-line arguments (6 or 7) */
|
|
|
|
|
char *argv[]) /* I - Command-line arguments */
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Can't print, so just reference the arguments to eliminate compiler
|
|
|
|
|
* warnings and return and exit status of 1. Normally you would use the
|
|
|
|
|
* arguments to send a file to the printer and return 0 if everything
|
|
|
|
|
* worked OK and non-zero if there was an error.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
(void)uri;
|
|
|
|
|
(void)hostname;
|
|
|
|
|
(void)resource;
|
|
|
|
|
(void)options;
|
|
|
|
|
(void)print_fd;
|
|
|
|
|
(void)copies;
|
|
|
|
|
(void)argc;
|
|
|
|
|
(void)argv;
|
|
|
|
|
|
|
|
|
|
return (CUPS_BACKEND_FAILED);
|
|
|
|
|
}
|
|
|
|
|
#endif /* HAVE_LIBUSB */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 'main()' - Send a file to the specified USB port.
|
|
|
|
|
*
|
|
|
|
|
* Usage:
|
|
|
|
|
*
|
|
|
|
|
* printer-uri job-id user title copies options [file]
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int /* O - Exit status */
|
|
|
|
|
main(int argc, /* I - Number of command-line arguments (6 or 7) */
|
|
|
|
|
char *argv[]) /* I - Command-line arguments */
|
|
|
|
|
{
|
|
|
|
|
int print_fd; /* Print file */
|
|
|
|
|
int copies; /* Number of copies to print */
|
|
|
|
|
int status; /* Exit status */
|
|
|
|
|
int port; /* Port number (not used) */
|
|
|
|
|
const char *uri; /* Device URI */
|
|
|
|
|
char method[255], /* Method in URI */
|
|
|
|
|
hostname[1024], /* Hostname */
|
|
|
|
|
username[255], /* Username info (not used) */
|
|
|
|
|
resource[1024], /* Resource info (device and options) */
|
|
|
|
|
*options; /* Pointer to options */
|
|
|
|
|
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
|
|
|
|
|
struct sigaction action; /* Actions for POSIX signals */
|
|
|
|
|
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure status messages are not buffered...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
setbuf(stderr, NULL);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ignore SIGPIPE signals...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SIGSET
|
|
|
|
|
sigset(SIGPIPE, SIG_IGN);
|
|
|
|
|
#elif defined(HAVE_SIGACTION)
|
|
|
|
|
memset(&action, 0, sizeof(action));
|
|
|
|
|
action.sa_handler = SIG_IGN;
|
|
|
|
|
sigaction(SIGPIPE, &action, NULL);
|
|
|
|
|
#else
|
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
|
#endif /* HAVE_SIGSET */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check command-line...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (argc == 1)
|
|
|
|
|
{
|
|
|
|
|
list_devices();
|
|
|
|
|
return (CUPS_BACKEND_OK);
|
|
|
|
|
}
|
|
|
|
|
else if (argc < 6 || argc > 7)
|
|
|
|
|
{
|
|
|
|
|
_cupsLangPrintf(stderr,
|
|
|
|
|
_("Usage: %s job-id user title copies options [file]"),
|
|
|
|
|
argv[0]);
|
|
|
|
|
return (CUPS_BACKEND_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Extract the device name and options from the URI...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
uri = cupsBackendDeviceURI(argv);
|
|
|
|
|
|
|
|
|
|
if (httpSeparateURI(HTTP_URI_CODING_ALL, uri,
|
|
|
|
|
method, sizeof(method), username, sizeof(username),
|
|
|
|
|
hostname, sizeof(hostname), &port,
|
|
|
|
|
resource, sizeof(resource)) < HTTP_URI_OK)
|
|
|
|
|
{
|
|
|
|
|
_cupsLangPrintFilter(stderr, "ERROR",
|
|
|
|
|
_("No device URI found in argv[0] or in DEVICE_URI "
|
|
|
|
|
"environment variable."));
|
|
|
|
|
return (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See if there are any options...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((options = strchr(resource, '?')) != NULL)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Yup, terminate the device name string and move to the first
|
|
|
|
|
* character of the options...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
*options++ = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we have 7 arguments, print the file named on the command-line.
|
|
|
|
|
* Otherwise, send stdin instead...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (argc == 6)
|
|
|
|
|
{
|
|
|
|
|
print_fd = 0;
|
|
|
|
|
copies = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Try to open the print file...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if ((print_fd = open(argv[6], O_RDONLY)) < 0)
|
|
|
|
|
{
|
|
|
|
|
_cupsLangPrintError("ERROR", _("Unable to open print file"));
|
|
|
|
|
return (CUPS_BACKEND_FAILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copies = atoi(argv[4]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Finally, send the print file...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
status = print_device(uri, hostname, resource, options, print_fd, copies,
|
|
|
|
|
argc, argv);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Close the input file and return...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (print_fd != 0)
|
|
|
|
|
close(print_fd);
|
|
|
|
|
|
|
|
|
|
return (status);
|
|
|
|
|
}
|