#include <cups/cups.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <cups/string.h>
#include <signal.h>
#ifdef WIN32
# include <io.h>
#else
# include <unistd.h>
# include <fcntl.h>
# include <termios.h>
#endif
#ifdef __linux
# include <sys/ioctl.h>
# include <linux/lp.h>
# define IOCNR_GET_DEVICE_ID 1
# define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
#endif
#ifdef __sun
# ifdef __sparc
# include <sys/ecppio.h>
# else
# include <sys/ecppsys.h>
# endif
#endif
void decode_device_id(int port, const char *device_id,
char *make_model, int mmsize,
char *uri, int urisize);
void list_devices(void);
int open_device(const char *uri);
int
main(int argc,
char *argv[])
{
int fp;
int copies;
int fd;
int wbytes;
size_t nbytes,
tbytes;
char buffer[8192],
*bufptr;
struct termios opts;
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action;
#endif
#ifdef __linux
unsigned char status;
#endif
setbuf(stderr, NULL);
#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
if (argc == 1)
{
list_devices();
return (0);
}
else if (argc < 6 || argc > 7)
{
fputs("Usage: USB job-id user title copies options [file]\n", stderr);
return (1);
}
if (argc == 6)
{
fp = 0;
copies = 1;
}
else
{
if ((fp = open(argv[6], O_RDONLY)) < 0)
{
perror("ERROR: unable to open print file");
return (1);
}
copies = atoi(argv[4]);
}
do
{
if ((fd = open_device(argv[0])) == -1)
{
if (errno == EBUSY)
{
fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr);
sleep(30);
}
else if (errno == ENXIO || errno == EIO || errno == ENOENT)
{
fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr);
sleep(30);
}
else
{
fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n",
argv[0], strerror(errno));
return (1);
}
}
}
while (fd < 0);
tcgetattr(fd, &opts);
opts.c_lflag &= ~(ICANON | ECHO | ISIG);
tcsetattr(fd, TCSANOW, &opts);
if (argc < 7)
{
#ifdef HAVE_SIGSET
sigset(SIGTERM, SIG_IGN);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_IGN;
sigaction(SIGTERM, &action, NULL);
#else
signal(SIGTERM, SIG_IGN);
#endif
}
#ifdef __linux
if (ioctl(fd, LPGETSTATUS, &status) == 0)
{
fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status);
if (status & LP_NOPA)
fputs("WARNING: Media tray empty!\n", stderr);
else if (status & LP_ERR)
fputs("WARNING: Printer fault!\n", stderr);
else if (status & LP_OFFL)
fputs("WARNING: Printer off-line.\n", stderr);
}
#endif
while (copies > 0)
{
copies --;
if (fp != 0)
{
fputs("PAGE: 1 1\n", stderr);
lseek(fp, 0, SEEK_SET);
}
tbytes = 0;
while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
{
tbytes += nbytes;
bufptr = buffer;
while (nbytes > 0)
{
if ((wbytes = write(fd, bufptr, nbytes)) < 0)
if (errno == ENOTTY)
wbytes = write(fd, bufptr, nbytes);
if (wbytes < 0)
{
perror("ERROR: Unable to send print file to printer");
break;
}
nbytes -= wbytes;
bufptr += wbytes;
}
if (argc > 6)
fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
(unsigned long)tbytes);
}
}
close(fd);
if (fp != 0)
close(fp);
fputs("INFO: Ready to print.\n", stderr);
return (0);
}
void
decode_device_id(int port,
const char *device_id,
char *make_model,
int mmsize,
char *uri,
int urisize)
{
char *attr,
*delim,
*uriptr,
*mfg,
*mdl,
serial_number[1024];
if ((attr = strstr(device_id, "DES:")) != NULL)
attr += 4;
else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL)
attr += 12;
if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL)
mfg += 13;
else if ((mfg = strstr(device_id, "MFG:")) != NULL)
mfg += 4;
if ((mdl = strstr(device_id, "MODEL:")) != NULL)
mdl += 6;
else if ((mdl = strstr(device_id, "MDL:")) != NULL)
mdl += 4;
if (attr)
{
if (strncasecmp(attr, "Hewlett-Packard ", 16) == 0)
{
strlcpy(make_model, "HP ", mmsize);
strlcpy(make_model + 3, attr + 16, mmsize - 3);
}
else
{
strlcpy(make_model, attr, mmsize);
}
if ((delim = strchr(make_model, ';')) != NULL)
*delim = '\0';
}
else if (mfg && mdl)
{
strlcpy(make_model, mfg, mmsize);
if ((delim = strchr(make_model, ';')) != NULL)
*delim = '\0';
strlcat(make_model, " ", mmsize);
strlcat(make_model, mdl, mmsize);
if ((delim = strchr(make_model, ';')) != NULL)
*delim = '\0';
}
else
{
strlcpy(make_model, "Unknown", mmsize);
}
if ((attr = strstr(device_id, "SERN:")) != NULL)
attr += 5;
else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL)
attr += 13;
if (attr)
{
strlcpy(serial_number, attr, sizeof(serial_number));
if ((delim = strchr(serial_number, ';')) != NULL)
*delim = '\0';
}
else
serial_number[0] = '\0';
strlcpy(uri, "usb://", urisize);
for (uriptr = uri + 6, delim = make_model;
*delim && uriptr < (uri + urisize - 1);
delim ++)
if (*delim == ' ')
{
delim ++;
*uriptr++ = '/';
break;
}
else
*uriptr++ = *delim;
for (; *delim && uriptr < (uri + urisize - 3); delim ++)
if (*delim == ' ')
{
*uriptr++ = '%';
*uriptr++ = '2';
*uriptr++ = '0';
}
else
*uriptr++ = *delim;
*uriptr = '\0';
if (serial_number[0])
{
strlcat(uri, "?serial=", urisize);
strlcat(uri, serial_number, urisize);
}
}
void
list_devices(void)
{
#ifdef __linux
int i;
int length;
int fd;
char format[255],
device[255],
device_id[1024],
device_uri[1024],
make_model[1024];
if (access("/dev/usb/lp0", 0) == 0)
strcpy(format, "/dev/usb/lp%d");
else if (access("/dev/usb/usblp0", 0) == 0)
strcpy(format, "/dev/usb/usblp%d");
else
strcpy(format, "/dev/usblp%d");
for (i = 0; i < 16; i ++)
{
sprintf(device, format, i);
if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
{
if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
{
length = (((unsigned)device_id[0] & 255) << 8) +
((unsigned)device_id[1] & 255);
if (length > (sizeof(device_id) - 2))
length = (((unsigned)device_id[1] & 255) << 8) +
((unsigned)device_id[0] & 255);
if (length > (sizeof(device_id) - 2))
length = sizeof(device_id) - 2;
memmove(device_id, device_id + 2, length);
device_id[length] = '\0';
}
else
device_id[0] = '\0';
close(fd);
}
else
device_id[0] = '\0';
if (device_id[0])
{
decode_device_id(i, device_id, make_model, sizeof(make_model),
device_uri, sizeof(device_uri));
printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
make_model, i + 1);
}
else
printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
}
#elif defined(__sgi)
#elif defined(__sun)
int i;
int fd;
char device[255],
device_id[1024],
device_uri[1024],
make_model[1024];
# ifdef ECPPIOC_GETDEVID
struct ecpp_device_id did;
# endif
for (i = 0; i < 8; i ++)
{
sprintf(device, "/dev/usb/printer%d", i);
# ifndef ECPPIOC_GETDEVID
if (!access(device, 0))
printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
# else
if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
{
did.mode = ECPP_CENTRONICS;
did.len = sizeof(device_id);
did.rlen = 0;
did.addr = device_id;
if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
{
if (did.rlen < (sizeof(device_id) - 1))
device_id[did.rlen] = '\0';
else
device_id[sizeof(device_id) - 1] = '\0';
}
else
device_id[0] = '\0';
close(fd);
}
else
device_id[0] = '\0';
if (device_id[0])
{
decode_device_id(i, device_id, make_model, sizeof(make_model),
device_uri, sizeof(device_uri));
printf("direct %s \"%s\" \"USB Printer #%d\"\n", device_uri,
make_model, i + 1);
}
else
printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
# endif
}
#elif defined(__hpux)
#elif defined(__osf)
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
int i;
char device[255];
for (i = 0; i < 8; i ++)
{
sprintf(device, "/dev/ulpt%d", i);
if (!access(device, 0))
printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
sprintf(device, "/dev/unlpt%d", i);
if (!access(device, 0))
printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1);
}
#endif
}
int
open_device(const char *uri)
{
if (strncmp(uri, "usb:/dev/", 9) == 0)
return (open(uri + 4, O_RDWR | O_EXCL));
#ifdef __linux
else if (strncmp(uri, "usb://", 6) == 0)
{
int i;
int length;
int fd;
char format[255],
device[255],
device_id[1024],
make_model[1024],
device_uri[1024];
if (access("/dev/usb/lp0", 0) == 0)
strcpy(format, "/dev/usb/lp%d");
else if (access("/dev/usb/usblp0", 0) == 0)
strcpy(format, "/dev/usb/usblp%d");
else
strcpy(format, "/dev/usblp%d");
for (i = 0; i < 16; i ++)
{
sprintf(device, format, i);
if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
{
if (ioctl(fd, LPIOC_GET_DEVICE_ID(sizeof(device_id)), device_id) == 0)
{
length = (((unsigned)device_id[0] & 255) << 8) +
((unsigned)device_id[1] & 255);
memmove(device_id, device_id + 2, length);
device_id[length] = '\0';
}
else
device_id[0] = '\0';
}
else
device_id[0] = '\0';
if (device_id[0])
{
decode_device_id(i, device_id, make_model, sizeof(make_model),
device_uri, sizeof(device_uri));
if (strcmp(uri, device_uri) == 0)
{
fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device);
return (fd);
}
}
close(fd);
}
errno = ENODEV;
return (-1);
}
#elif defined(__sun) && defined(ECPPIOC_GETDEVID)
else if (strncmp(uri, "usb://", 6) == 0)
{
int i;
int fd;
char device[255],
device_id[1024],
make_model[1024],
device_uri[1024];
struct ecpp_device_id did;
for (i = 0; i < 8; i ++)
{
sprintf(device, "/dev/usb/printer%d", i);
if ((fd = open(device, O_RDWR | O_EXCL)) >= 0)
{
did.mode = ECPP_CENTRONICS;
did.len = sizeof(device_id);
did.rlen = 0;
did.addr = device_id;
if (ioctl(fd, ECPPIOC_GETDEVID, &did) == 0)
{
if (did.rlen < (sizeof(device_id) - 1))
device_id[did.rlen] = '\0';
else
device_id[sizeof(device_id) - 1] = '\0';
}
else
device_id[0] = '\0';
}
else
device_id[0] = '\0';
if (device_id[0])
{
decode_device_id(i, device_id, make_model, sizeof(make_model),
device_uri, sizeof(device_uri));
if (strcmp(uri, device_uri) == 0)
return (fd);
}
close(fd);
}
errno = ENODEV;
return (-1);
}
#endif
else
{
errno = ENODEV;
return (-1);
}
}