home *** CD-ROM | disk | FTP | other *** search
- /* lprps.c */
-
- #ifndef lint
- static char rcsid[] = "$Header: /usr/jjc/lprps/RCS/lprps.c,v 1.7 90/12/18 10:07:24 jjc Rel $";
- #endif
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/ioctl.h>
- #include <sys/file.h>
- #include <fcntl.h>
- #include <sys/time.h>
- #include <signal.h>
- #include <syslog.h>
- #include <errno.h>
-
- #define EXIT_SUCCESS 0
- #define EXIT_REPRINT 1
- #define EXIT_THROW_AWAY 2
-
- #define OBSIZE 1024
- #define IBSIZE 1024
-
- char *mktemp();
- char *sprintf(); /* sigh */
-
- char *login;
- char *host;
- char *accounting_file;
- FILE *mailfp;
- int interrupt_flag = 0;
- int timeout_flag = 0;
- int psfd;
- /* number of 004s received from printer */
- int eof_count = 0;
- /* if non-zero ignore all input from printer other than 004s */
- int ignore_input = 0;
- /* are we currently printing the users job */
- int in_job = 0;
-
- enum {
- NORMAL,
- HAD_ONE_PERCENT,
- HAD_TWO_PERCENT,
- IN_MESSAGE,
- HAD_RIGHT_BRACKET,
- HAD_RIGHT_BRACKET_AND_PERCENT
- } parse_state;
-
- enum {
- INVALID,
- UNKNOWN,
- IDLE,
- BUSY,
- WAITING
- } status = INVALID;
-
- int start_pagecount = -1;
- int end_pagecount = -1;
-
- struct {
- char *ptr;
- int count;
- char buf[OBSIZE];
- } out = { out.buf, OBSIZE };
-
- #define MBSIZE 1024
-
- char message_buf[MBSIZE];
- int message_buf_i;
-
- static char temp_file[] = "/tmp/lprpsXXXXXX";
-
- static char pagecount_string[] = "(%%[ pagecount: ) print \
- statusdict begin pagecount end 20 string cvs print \
- ( ]%%) print flush\n";
-
- void process_input_char();
- void printer_flushing();
- void handle_interrupt();
- void do_exit();
-
- void handle_timeout()
- {
- syslog(LOG_ERR, "printer not responding");
- sleep(60); /* it will take at least this long to warm up */
- do_exit(EXIT_REPRINT);
- }
-
- void sys_error(s)
- char *s;
- {
- syslog(LOG_ERR, "%s: %m", s);
- exit(EXIT_THROW_AWAY);
- }
-
- int blocking_flag = 1;
-
- void set_blocking()
- {
- if (!blocking_flag) {
- if (fcntl(psfd, F_SETFL, 0) == -1)
- sys_error("fcntl");
- blocking_flag = 1;
- }
- }
-
- void set_non_blocking()
- {
- if (blocking_flag) {
- if (fcntl(psfd, F_SETFL, FNDELAY) == -1)
- sys_error("fcntl");
- blocking_flag = 0;
- }
- }
-
- void blocking_write(s, n)
- char *s;
- int n;
- {
- set_blocking();
- if (write(psfd, s, n) == -1)
- sys_error("write");
- }
-
- void ioflush()
- {
- int rw = FREAD|FWRITE;
- if (ioctl(psfd, TIOCFLUSH, &rw) == -1)
- sys_error("ioctl(TIOCFLUSH)");
- }
-
- void open_mailfp()
- {
- if (mailfp == 0) {
- (void)mktemp(temp_file);
- if ((mailfp = fopen(temp_file, "w")) == NULL)
- sys_error("open");
- }
- }
-
- void user_char(c)
- char c;
- {
- static int done_intro = 0;
- if (in_job && (done_intro || c != '\n')) {
- if (mailfp == 0)
- open_mailfp();
- if (!done_intro) {
- fputs("Your PostScript printer job produced the following output:\n",
- mailfp);
- done_intro = 1;
- }
- (void)putc(c, mailfp);
- }
- }
-
- #if 0
- void init_tty()
- {
- struct termios t;
- psfd = open("/dev/ttya", O_RDWR);
- if (psfd == -1)
- sys_error("open");
- if (ioctl(psfd, TCGETS, &t) == -1)
- sys_error("ioctl(TCGETS)");
- t.c_cflag = B38400|CS7|CSTOPB|CREAD|CLOCAL|PARENB;
- t.c_oflag &= ~OPOST;
- t.c_iflag = IXON|IXOFF|IGNBRK|ISTRIP|IGNCR;
- t.c_lflag = 0;
- t.c_cc[VMIN] = 1;
- t.c_cc[VTIME] = 0;
- if (ioctl(psfd, TCSETS, &t) == -1)
- sys_error("ioctl(TCSETS)");
- }
-
- void debug_tty()
- {
- struct termios t;
- if (ioctl(psfd, TCGETS, &t) == -1)
- sys_error("ioctl(TCGETS)");
- syslog(LOG_ERR, "cflag = %o", t.c_cflag);
- syslog(LOG_ERR, "oflag = %o", t.c_oflag);
- syslog(LOG_ERR, "lflag = %o", t.c_lflag);
- syslog(LOG_ERR, "iflag = %o", t.c_iflag);
- }
- #endif
-
- void do_exit(exit_code)
- int exit_code;
- {
- if (mailfp != NULL) {
- char command[1024];
- if (fclose(mailfp) == EOF)
- sys_error("fclose");
- (void)sprintf(command, "/usr/ucb/mail -s \"printer job\" %s@%s <%s",
- login, host, temp_file);
- (void)system(command);
- (void)unlink(temp_file);
- }
- exit(exit_code);
- }
-
- void flush_output()
- {
- char ibuf[IBSIZE];
- char *p = out.buf;
- int n = out.ptr - p;
- /* we daren't block on writes */
- set_non_blocking();
- while (n > 0) {
- fd_set rfds, wfds;
- FD_ZERO(&wfds);
- FD_ZERO(&rfds);
- FD_SET(psfd, &wfds);
- FD_SET(psfd, &rfds);
- if (interrupt_flag)
- handle_interrupt();
- while (select(psfd + 1, &rfds, &wfds, (fd_set *)NULL, (struct timeval *)NULL)
- == -1)
- if (errno == EINTR) {
- if (timeout_flag)
- handle_timeout();
- else if (interrupt_flag)
- handle_interrupt();
- }
- else
- sys_error("select");
- if (FD_ISSET(psfd, &rfds)) {
- char *q = ibuf;
- int nread = read(psfd, ibuf, IBSIZE);
- if (nread == -1)
- sys_error("read");
- while (--nread >= 0)
- process_input_char(*q++);
- }
- else if (FD_ISSET(psfd, &wfds)) {
- int nwritten = write(psfd, p, n);
- if (nwritten == -1)
- sys_error("write");
- n -= nwritten;
- p += nwritten;
- }
- }
- out.ptr = out.buf;
- out.count = OBSIZE;
- }
-
-
- void output_char(c)
- char c;
- {
- if (out.count <= 0)
- flush_output();
- *out.ptr = c;
- out.ptr += 1;
- out.count -= 1;
- }
-
- void message_char(c)
- char c;
- {
- if (c != '\0' && message_buf_i < MBSIZE - 1)
- message_buf[message_buf_i++] = c;
- }
-
- void process_message()
- {
- char *p;
- message_buf[message_buf_i] = 0;
- for (p = strtok(message_buf, ";"); p != NULL; p = strtok((char *)NULL, ";")) {
- char *key;
- while (isspace(*p))
- p++;
- key = p;
- p = strchr(p, ':');
- if (p != NULL) {
- char *q;
- *p++ = '\0';
- while (isspace(*p))
- p++;
- q = strchr(p, '\0');
- while (q > p && isspace(q[-1]))
- --q;
- *q = '\0';
- if (strcmp(key, "Flushing") == 0)
- printer_flushing();
- else if (strcmp(key, "PrinterError") == 0) {
- syslog(LOG_ERR, "printer error: %s", p);
- }
- else if (strcmp(key, "exitserver") == 0) {
- }
- else if (strcmp(key, "Error") == 0) {
- if (in_job) {
- if (mailfp == 0)
- open_mailfp();
- (void)fprintf(mailfp,
- "Your PostScript printer job produced the error `%s'.\n",
- p);
- }
- }
- else if (strcmp(key, "status") == 0) {
- if (strcmp(p, "idle") == 0)
- status = IDLE;
- else if (strcmp(p, "busy") == 0)
- status = BUSY;
- else if (strcmp(p, "waiting") == 0)
- status = WAITING;
- else
- status = UNKNOWN;
- }
- else if (strcmp(key, "OffendingCommand") == 0) {
- if (in_job) {
- if (mailfp == 0)
- open_mailfp();
- (void)fprintf(mailfp, "The offending command was `%s'.\n", p);
- }
- }
- else if (strcmp(key, "pagecount") == 0) {
- int n;
- if (sscanf(p, "%d", &n) == 1 && n >= 0) {
- if (start_pagecount < 0)
- start_pagecount = n;
- else
- end_pagecount = n;
- }
- }
- }
- }
- }
-
-
- void process_input_char(c)
- char c;
- {
- if (c == '\004')
- ++eof_count;
- else if (ignore_input) {
- }
- else {
- switch (parse_state) {
- case NORMAL:
- if (c == '%')
- parse_state = HAD_ONE_PERCENT;
- else
- user_char(c);
- break;
- case HAD_ONE_PERCENT:
- if (c == '%')
- parse_state = HAD_TWO_PERCENT;
- else {
- user_char('%');
- user_char(c);
- parse_state = NORMAL;
- }
- break;
- case HAD_TWO_PERCENT:
- if (c == '[') {
- message_buf_i = 0;
- parse_state = IN_MESSAGE;
- }
- else {
- user_char('%');
- user_char('%');
- user_char(c);
- parse_state = NORMAL;
- }
- break;
- case IN_MESSAGE:
- if (c == ']')
- parse_state = HAD_RIGHT_BRACKET;
- else
- message_char(c);
- break;
- case HAD_RIGHT_BRACKET:
- if (c == '%')
- parse_state = HAD_RIGHT_BRACKET_AND_PERCENT;
- else {
- message_char(']');
- message_char(c);
- parse_state = IN_MESSAGE;
- }
- break;
- case HAD_RIGHT_BRACKET_AND_PERCENT:
- if (c == '%') {
- parse_state = NORMAL;
- process_message();
- }
- else {
- message_char(']');
- message_char('%');
- message_char(c);
- parse_state = IN_MESSAGE;
- }
- break;
- default:
- abort();
- }
- }
- }
-
-
- void process_some_input()
- {
- char ibuf[IBSIZE];
- char *p = ibuf;
- int nread;
- fd_set rfds, wfds;
- set_non_blocking();
- FD_ZERO(&wfds);
- FD_ZERO(&rfds);
- FD_SET(psfd, &rfds);
- if (interrupt_flag)
- handle_interrupt();
- if (timeout_flag)
- handle_timeout();
- /* select is not restarted if interrupted, whereas read is */
- while (select(psfd + 1, &rfds, &wfds, (fd_set *)NULL, (struct timeval *)NULL)
- == -1)
- if (errno == EINTR) {
- if (timeout_flag)
- handle_timeout();
- else if (interrupt_flag)
- handle_interrupt();
- }
- else
- sys_error("select");
- nread = read(psfd, ibuf, IBSIZE);
- if (nread == -1)
- sys_error("read");
- if (nread == 0)
- sys_error("read returned 0");
- while (--nread >= 0)
- process_input_char(*p++);
- }
-
-
- void do_accounting()
- {
- FILE *fp;
- if (end_pagecount > start_pagecount
- && accounting_file != NULL
- && (fp = fopen(accounting_file, "a")) != NULL) {
- (void)fprintf(fp,
- "%7.2f %s:%s\n",
- (double)(end_pagecount - start_pagecount),
- host,
- login);
- if (fclose(fp) == EOF)
- sys_error("fclose");
- }
- }
-
- void set_timeout_flag()
- {
- timeout_flag = 1;
- }
-
- void get_end_pagecount()
- {
- char c;
- int ec;
- if (signal(SIGALRM, set_timeout_flag) == BADSIG)
- sys_error("signal");
- (void)alarm(30);
- ioflush();
- blocking_write(pagecount_string, sizeof(pagecount_string) - 1);
- end_pagecount = -1;
- ignore_input = 0;
- in_job = 0;
- parse_state = NORMAL;
- while (end_pagecount < 0)
- process_some_input();
- c = '\004';
- blocking_write(&c, 1);
- ec = eof_count;
- while (ec == eof_count)
- process_some_input();
- if (signal(SIGALRM, SIG_IGN) == BADSIG)
- sys_error("signal");
- }
-
- void get_start_pagecount()
- {
- char c;
- int ec;
- if (signal(SIGALRM, set_timeout_flag) == BADSIG)
- sys_error("signal");
- (void)alarm(30);
- ioflush();
- blocking_write(pagecount_string, sizeof(pagecount_string) - 1);
- start_pagecount = -1;
- parse_state = NORMAL;
- in_job = 0;
- ignore_input = 0;
- while (start_pagecount < 0)
- process_some_input();
- c = '\004';
- blocking_write(&c, 1);
- ec = eof_count;
- while (ec == eof_count)
- process_some_input();
- if (signal(SIGALRM, SIG_IGN) == BADSIG)
- sys_error("signal");
- }
-
- void set_interrupt_flag()
- {
- interrupt_flag = 1;
- }
-
- void handle_interrupt()
- {
- static char interrupt_string[] = "\003\004";
- int ec;
- interrupt_flag = 0;
- if (signal(SIGINT, SIG_IGN) == BADSIG)
- sys_error("signal");
- if (signal(SIGALRM, set_timeout_flag) == BADSIG)
- sys_error("signal");
- (void)alarm(30);
- ioflush();
- blocking_write(interrupt_string, sizeof(interrupt_string)-1);
- ignore_input = 1;
- ec = eof_count;
- while (eof_count == ec)
- process_some_input();
- if (signal(SIGALRM, SIG_IGN) == BADSIG)
- sys_error("signal");
- get_end_pagecount();
- do_accounting();
- do_exit(EXIT_SUCCESS);
- }
-
- void printer_flushing()
- {
- int ec;
- char c = '\004';
- if (signal(SIGINT, SIG_IGN) == BADSIG)
- sys_error("signal");
- ioflush();
- blocking_write(&c, 1);
- ignore_input = 1;
- ec = eof_count;
- while (eof_count == ec)
- process_some_input();
- get_end_pagecount();
- do_accounting();
- do_exit(EXIT_SUCCESS);
- }
-
- void send_file()
- {
- char c;
- int ec;
- in_job = 1;
- parse_state = NORMAL;
- ignore_input = 0;
- if (signal(SIGINT, set_interrupt_flag) == BADSIG)
- sys_error("signal");
- while ((c = getchar()) != EOF)
- output_char(c);
- flush_output();
- c = '\004';
- blocking_write(&c, 1);
- ec = eof_count;
- while (ec == eof_count)
- process_some_input();
- }
-
- void get_status()
- {
- char c = '\024';
- if (signal(SIGALRM, set_timeout_flag) == BADSIG)
- sys_error("signal");
- ioflush();
- (void)alarm(5);
- blocking_write(&c, 1);
- in_job = 0;
- parse_state = NORMAL;
- ignore_input = 0;
- while (status == INVALID)
- process_some_input();
- switch (status) {
- case IDLE:
- break;
- case WAITING:
- c = '\004';
- blocking_write(&c, 1);
- sleep(5);
- exit(EXIT_REPRINT);
- case BUSY:
- case UNKNOWN:
- sleep(15);
- exit(EXIT_REPRINT);
- }
- if (signal(SIGALRM, SIG_IGN) == BADSIG)
- sys_error("signal");
- }
-
- void usage()
- {
- syslog(LOG_ERR, "usage");
- exit(EXIT_THROW_AWAY);
- }
-
- int main(argc, argv)
- int argc;
- char **argv;
- {
- int i = 1;
- openlog("lprps", LOG_PID, LOG_LPR);
- while (i < argc && argv[i][0] == '-') {
- switch (argv[i][1]) {
- case 'c':
- break;
- case 'x':
- case 'y':
- case 'w':
- case 'l':
- case 'i':
- break;
- case 'n':
- if (++i == argc)
- usage();
- else
- login = argv[i];
- break;
- case 'h':
- if (++i == argc)
- usage();
- else
- host = argv[i];
-
- break;
- default:
- usage();
- }
- ++i;
- }
- if (i < argc)
- accounting_file = argv[i];
- psfd = 1;
- get_status();
- get_start_pagecount();
- send_file();
- get_end_pagecount();
- do_accounting();
- do_exit(EXIT_SUCCESS);
- }
-
-