home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2351 / lprps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  12.4 KB  |  654 lines

  1. /* lprps.c */
  2.  
  3. #ifndef lint
  4. static char rcsid[] = "$Header: /usr/jjc/lprps/RCS/lprps.c,v 1.7 90/12/18 10:07:24 jjc Rel $";
  5. #endif
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <sys/ioctl.h>
  12. #include <sys/file.h>
  13. #include <fcntl.h>
  14. #include <sys/time.h>
  15. #include <signal.h>
  16. #include <syslog.h>
  17. #include <errno.h>
  18.  
  19. #define EXIT_SUCCESS 0
  20. #define EXIT_REPRINT 1
  21. #define EXIT_THROW_AWAY 2
  22.  
  23. #define OBSIZE 1024
  24. #define IBSIZE 1024
  25.  
  26. char *mktemp();
  27. char *sprintf(); /* sigh */
  28.  
  29. char *login;
  30. char *host;
  31. char *accounting_file;
  32. FILE *mailfp;
  33. int interrupt_flag = 0;
  34. int timeout_flag = 0;
  35. int psfd;
  36. /* number of 004s received from printer */
  37. int eof_count = 0;
  38. /* if non-zero ignore all input from printer other than 004s */
  39. int ignore_input = 0;
  40. /* are we currently printing the users job */
  41. int in_job = 0;
  42.  
  43. enum {
  44.   NORMAL,
  45.   HAD_ONE_PERCENT,
  46.   HAD_TWO_PERCENT,
  47.   IN_MESSAGE,
  48.   HAD_RIGHT_BRACKET,
  49.   HAD_RIGHT_BRACKET_AND_PERCENT
  50.   } parse_state;
  51.  
  52. enum {
  53.   INVALID,
  54.   UNKNOWN,
  55.   IDLE,
  56.   BUSY,
  57.   WAITING
  58.   } status = INVALID;
  59.  
  60. int start_pagecount = -1;
  61. int end_pagecount = -1;
  62.  
  63. struct {
  64.   char *ptr;
  65.   int count;
  66.   char buf[OBSIZE];
  67. } out = { out.buf, OBSIZE };
  68.  
  69. #define MBSIZE 1024
  70.  
  71. char message_buf[MBSIZE];
  72. int message_buf_i;
  73.  
  74. static char temp_file[] = "/tmp/lprpsXXXXXX";
  75.  
  76. static char pagecount_string[] = "(%%[ pagecount: ) print \
  77. statusdict begin pagecount end 20 string cvs print \
  78. ( ]%%) print flush\n";
  79.  
  80. void process_input_char();
  81. void printer_flushing();
  82. void handle_interrupt();
  83. void do_exit();
  84.  
  85. void handle_timeout()
  86. {
  87.   syslog(LOG_ERR, "printer not responding");
  88.   sleep(60);        /* it will take at least this long to warm up */
  89.   do_exit(EXIT_REPRINT);
  90. }
  91.  
  92. void sys_error(s)
  93. char *s;
  94. {
  95.   syslog(LOG_ERR, "%s: %m", s);
  96.   exit(EXIT_THROW_AWAY);
  97. }
  98.  
  99. int blocking_flag = 1;
  100.  
  101. void set_blocking()
  102. {
  103.   if (!blocking_flag) {
  104.     if (fcntl(psfd, F_SETFL, 0) == -1)
  105.       sys_error("fcntl");
  106.     blocking_flag = 1;
  107.   }
  108. }
  109.  
  110. void set_non_blocking()
  111. {
  112.   if (blocking_flag) {
  113.     if (fcntl(psfd, F_SETFL, FNDELAY) == -1)
  114.       sys_error("fcntl");
  115.     blocking_flag = 0;
  116.   }
  117. }
  118.  
  119. void blocking_write(s, n)
  120. char *s;
  121. int n;
  122. {
  123.   set_blocking();
  124.   if (write(psfd, s, n) == -1)
  125.     sys_error("write");
  126. }
  127.  
  128. void ioflush()
  129. {
  130.   int rw = FREAD|FWRITE;
  131.   if (ioctl(psfd, TIOCFLUSH, &rw) == -1)
  132.     sys_error("ioctl(TIOCFLUSH)");
  133. }
  134.  
  135. void open_mailfp()
  136. {
  137.   if (mailfp == 0) {
  138.     (void)mktemp(temp_file);
  139.     if ((mailfp = fopen(temp_file, "w")) == NULL)
  140.       sys_error("open");
  141.   }
  142. }
  143.  
  144. void user_char(c)
  145. char c;
  146. {
  147.   static int done_intro = 0;
  148.   if (in_job && (done_intro || c != '\n')) {
  149.     if (mailfp == 0)
  150.       open_mailfp();
  151.     if (!done_intro) {
  152.       fputs("Your PostScript printer job produced the following output:\n", 
  153.         mailfp);
  154.       done_intro = 1;
  155.     }
  156.     (void)putc(c, mailfp);
  157.   }
  158. }
  159.  
  160. #if 0
  161. void init_tty()
  162. {
  163.   struct termios t;
  164.   psfd = open("/dev/ttya", O_RDWR);
  165.   if (psfd == -1)
  166.     sys_error("open");
  167.   if (ioctl(psfd, TCGETS, &t) == -1)
  168.     sys_error("ioctl(TCGETS)");
  169.   t.c_cflag = B38400|CS7|CSTOPB|CREAD|CLOCAL|PARENB;
  170.   t.c_oflag &= ~OPOST;
  171.   t.c_iflag = IXON|IXOFF|IGNBRK|ISTRIP|IGNCR;
  172.   t.c_lflag = 0;
  173.   t.c_cc[VMIN] = 1;
  174.   t.c_cc[VTIME] = 0;
  175.   if (ioctl(psfd, TCSETS, &t) == -1)
  176.     sys_error("ioctl(TCSETS)");
  177. }
  178.  
  179. void debug_tty()
  180. {
  181.   struct termios t;
  182.   if (ioctl(psfd, TCGETS, &t) == -1)
  183.     sys_error("ioctl(TCGETS)");
  184.   syslog(LOG_ERR, "cflag = %o", t.c_cflag);
  185.   syslog(LOG_ERR, "oflag = %o", t.c_oflag);
  186.   syslog(LOG_ERR, "lflag = %o", t.c_lflag);
  187.   syslog(LOG_ERR, "iflag = %o", t.c_iflag);
  188. }
  189. #endif
  190.  
  191. void do_exit(exit_code)
  192. int exit_code;
  193. {
  194.   if (mailfp != NULL) {
  195.     char command[1024];
  196.     if (fclose(mailfp) == EOF)
  197.       sys_error("fclose");
  198.     (void)sprintf(command, "/usr/ucb/mail -s \"printer job\" %s@%s <%s",
  199.         login, host, temp_file);
  200.     (void)system(command);
  201.     (void)unlink(temp_file);
  202.   }
  203.   exit(exit_code);
  204. }
  205.   
  206. void flush_output()
  207. {
  208.   char ibuf[IBSIZE];
  209.   char *p = out.buf;
  210.   int n = out.ptr - p;
  211.   /* we daren't block on writes */
  212.   set_non_blocking();
  213.   while (n > 0) {
  214.     fd_set rfds, wfds;
  215.     FD_ZERO(&wfds);
  216.     FD_ZERO(&rfds);
  217.     FD_SET(psfd, &wfds);
  218.     FD_SET(psfd, &rfds);
  219.     if (interrupt_flag)
  220.       handle_interrupt();
  221.     while (select(psfd + 1, &rfds, &wfds, (fd_set *)NULL, (struct timeval *)NULL)
  222.        == -1)
  223.       if (errno == EINTR) {
  224.     if (timeout_flag)
  225.       handle_timeout();
  226.     else if (interrupt_flag)
  227.       handle_interrupt();
  228.       }
  229.       else
  230.     sys_error("select");
  231.     if (FD_ISSET(psfd, &rfds)) {
  232.       char *q = ibuf;
  233.       int nread = read(psfd, ibuf, IBSIZE);
  234.       if (nread == -1)
  235.     sys_error("read");
  236.       while (--nread >= 0)
  237.     process_input_char(*q++);
  238.     }
  239.     else if (FD_ISSET(psfd, &wfds)) {
  240.       int nwritten = write(psfd, p, n);
  241.       if (nwritten == -1)
  242.     sys_error("write");
  243.       n -= nwritten;
  244.       p += nwritten;
  245.     }
  246.   }
  247.   out.ptr = out.buf;
  248.   out.count = OBSIZE;
  249. }
  250.  
  251.   
  252. void output_char(c)
  253. char c;
  254. {
  255.   if (out.count <= 0)
  256.     flush_output();
  257.   *out.ptr = c;
  258.   out.ptr += 1;
  259.   out.count -= 1;
  260. }
  261.  
  262. void message_char(c)
  263. char c;
  264. {
  265.   if (c != '\0' && message_buf_i < MBSIZE - 1)
  266.     message_buf[message_buf_i++] = c;
  267. }
  268.  
  269. void process_message()
  270. {
  271.   char *p;
  272.   message_buf[message_buf_i] = 0;
  273.   for (p = strtok(message_buf, ";"); p != NULL; p = strtok((char *)NULL, ";")) {
  274.     char *key;
  275.     while (isspace(*p))
  276.       p++;
  277.     key = p;
  278.     p = strchr(p, ':');
  279.     if (p != NULL) {
  280.       char *q;
  281.       *p++ = '\0';
  282.       while (isspace(*p))
  283.     p++;
  284.       q = strchr(p, '\0');
  285.       while (q > p && isspace(q[-1]))
  286.     --q;
  287.       *q = '\0';
  288.       if (strcmp(key, "Flushing") == 0)
  289.     printer_flushing();
  290.       else if (strcmp(key, "PrinterError") == 0) {
  291.     syslog(LOG_ERR, "printer error: %s", p);
  292.       }
  293.       else if (strcmp(key, "exitserver") == 0) {
  294.       }
  295.       else if (strcmp(key, "Error") == 0) {
  296.     if (in_job) {
  297.       if (mailfp == 0)
  298.         open_mailfp();
  299.       (void)fprintf(mailfp, 
  300.             "Your PostScript printer job produced the error `%s'.\n",
  301.             p);
  302.     }
  303.       }
  304.       else if (strcmp(key, "status") == 0) {
  305.     if (strcmp(p, "idle") == 0)
  306.       status = IDLE;
  307.     else if (strcmp(p, "busy") == 0)
  308.       status = BUSY;
  309.     else if (strcmp(p, "waiting") == 0)
  310.       status = WAITING;
  311.     else
  312.       status = UNKNOWN;
  313.       }
  314.       else if (strcmp(key, "OffendingCommand") == 0) {
  315.     if (in_job) {
  316.       if (mailfp == 0)
  317.         open_mailfp();
  318.       (void)fprintf(mailfp, "The offending command was `%s'.\n", p);
  319.     }
  320.       }
  321.       else if (strcmp(key, "pagecount") == 0) {
  322.     int n;
  323.     if (sscanf(p, "%d", &n) == 1 && n >= 0) {
  324.       if (start_pagecount < 0)
  325.         start_pagecount = n;
  326.       else
  327.         end_pagecount = n;
  328.     }
  329.       }
  330.     }
  331.   }
  332. }
  333.  
  334.  
  335. void process_input_char(c)
  336. char c;
  337. {
  338.   if (c == '\004')
  339.     ++eof_count;
  340.   else if (ignore_input) {
  341.   }
  342.   else {
  343.     switch (parse_state) {
  344.     case NORMAL:
  345.       if (c == '%')
  346.     parse_state = HAD_ONE_PERCENT;
  347.       else
  348.     user_char(c);
  349.       break;
  350.     case HAD_ONE_PERCENT:
  351.       if (c == '%')
  352.     parse_state = HAD_TWO_PERCENT;
  353.       else {
  354.     user_char('%');
  355.     user_char(c);
  356.     parse_state = NORMAL;
  357.       }
  358.       break;
  359.     case HAD_TWO_PERCENT:
  360.       if (c == '[') {
  361.     message_buf_i = 0;
  362.     parse_state = IN_MESSAGE;
  363.       }
  364.       else {
  365.     user_char('%');
  366.     user_char('%');
  367.     user_char(c);
  368.     parse_state = NORMAL;
  369.       }
  370.       break;
  371.     case IN_MESSAGE:
  372.       if (c == ']')
  373.     parse_state = HAD_RIGHT_BRACKET;
  374.       else
  375.     message_char(c);
  376.       break;
  377.     case HAD_RIGHT_BRACKET:
  378.       if (c == '%')
  379.     parse_state = HAD_RIGHT_BRACKET_AND_PERCENT;
  380.       else {
  381.     message_char(']');
  382.     message_char(c);
  383.     parse_state = IN_MESSAGE;
  384.       }
  385.       break;
  386.     case HAD_RIGHT_BRACKET_AND_PERCENT:
  387.       if (c == '%') {
  388.     parse_state = NORMAL;
  389.     process_message();
  390.       }
  391.       else {
  392.     message_char(']');
  393.     message_char('%');
  394.     message_char(c);
  395.     parse_state = IN_MESSAGE;
  396.       }
  397.       break;
  398.     default:
  399.       abort();
  400.     }
  401.   }
  402. }
  403.  
  404.  
  405. void process_some_input()
  406. {
  407.   char ibuf[IBSIZE];
  408.   char *p = ibuf;
  409.   int nread;
  410.   fd_set rfds, wfds;
  411.   set_non_blocking();
  412.   FD_ZERO(&wfds);
  413.   FD_ZERO(&rfds);
  414.   FD_SET(psfd, &rfds);
  415.   if (interrupt_flag)
  416.     handle_interrupt();
  417.   if (timeout_flag)
  418.     handle_timeout();
  419.   /* select is not restarted if interrupted, whereas read is */
  420.   while (select(psfd + 1, &rfds, &wfds, (fd_set *)NULL, (struct timeval *)NULL) 
  421.      == -1)
  422.     if (errno == EINTR) {
  423.       if (timeout_flag)
  424.     handle_timeout();
  425.       else if (interrupt_flag)
  426.     handle_interrupt();
  427.     }
  428.     else
  429.       sys_error("select");
  430.   nread = read(psfd, ibuf, IBSIZE);
  431.   if (nread == -1)
  432.     sys_error("read");
  433.   if (nread == 0)
  434.     sys_error("read returned 0");
  435.   while (--nread >= 0)
  436.     process_input_char(*p++);
  437. }
  438.  
  439.  
  440. void do_accounting()
  441. {
  442.   FILE *fp;
  443.   if (end_pagecount > start_pagecount
  444.       && accounting_file != NULL
  445.       && (fp = fopen(accounting_file, "a")) != NULL) {
  446.     (void)fprintf(fp,
  447.         "%7.2f %s:%s\n", 
  448.         (double)(end_pagecount - start_pagecount),
  449.         host,
  450.         login);
  451.     if (fclose(fp) == EOF)
  452.       sys_error("fclose");
  453.   }
  454. }
  455.  
  456. void set_timeout_flag()
  457. {
  458.   timeout_flag = 1;
  459. }
  460.  
  461. void get_end_pagecount()
  462. {
  463.   char c;
  464.   int ec;
  465.   if (signal(SIGALRM, set_timeout_flag) == BADSIG)
  466.     sys_error("signal");
  467.   (void)alarm(30);
  468.   ioflush();
  469.   blocking_write(pagecount_string, sizeof(pagecount_string) - 1);
  470.   end_pagecount = -1;
  471.   ignore_input = 0;
  472.   in_job = 0;
  473.   parse_state = NORMAL;
  474.   while (end_pagecount < 0)
  475.     process_some_input();
  476.   c = '\004';
  477.   blocking_write(&c, 1);
  478.   ec = eof_count;
  479.   while (ec == eof_count)
  480.     process_some_input();
  481.   if (signal(SIGALRM, SIG_IGN) == BADSIG)
  482.     sys_error("signal");
  483. }
  484.  
  485. void get_start_pagecount()
  486. {
  487.   char c;
  488.   int ec;
  489.   if (signal(SIGALRM, set_timeout_flag) == BADSIG)
  490.     sys_error("signal");
  491.   (void)alarm(30);
  492.   ioflush();
  493.   blocking_write(pagecount_string, sizeof(pagecount_string) - 1);
  494.   start_pagecount = -1;
  495.   parse_state = NORMAL;
  496.   in_job = 0;
  497.   ignore_input = 0;
  498.   while (start_pagecount < 0)
  499.     process_some_input();
  500.   c = '\004';
  501.   blocking_write(&c, 1);
  502.   ec = eof_count;
  503.   while (ec == eof_count)
  504.     process_some_input();
  505.   if (signal(SIGALRM, SIG_IGN) == BADSIG)
  506.     sys_error("signal");
  507. }
  508.  
  509. void set_interrupt_flag()
  510. {
  511.   interrupt_flag = 1;
  512. }
  513.  
  514. void handle_interrupt()
  515. {
  516.   static char interrupt_string[] = "\003\004";
  517.   int ec;
  518.   interrupt_flag = 0;
  519.   if (signal(SIGINT, SIG_IGN) == BADSIG)
  520.     sys_error("signal");
  521.   if (signal(SIGALRM, set_timeout_flag) == BADSIG)
  522.     sys_error("signal");
  523.   (void)alarm(30);
  524.   ioflush();
  525.   blocking_write(interrupt_string, sizeof(interrupt_string)-1);
  526.   ignore_input = 1;
  527.   ec = eof_count;
  528.   while (eof_count == ec)
  529.     process_some_input();
  530.   if (signal(SIGALRM, SIG_IGN) == BADSIG)
  531.     sys_error("signal");
  532.   get_end_pagecount();
  533.   do_accounting();
  534.   do_exit(EXIT_SUCCESS);
  535. }
  536.  
  537. void printer_flushing()
  538. {
  539.   int ec;
  540.   char c = '\004';
  541.   if (signal(SIGINT, SIG_IGN) == BADSIG)
  542.     sys_error("signal");
  543.   ioflush();
  544.   blocking_write(&c, 1);
  545.   ignore_input = 1;
  546.   ec = eof_count;
  547.   while (eof_count == ec)
  548.     process_some_input();
  549.   get_end_pagecount();
  550.   do_accounting();
  551.   do_exit(EXIT_SUCCESS);
  552. }
  553.  
  554. void send_file()
  555. {
  556.   char c;
  557.   int ec;
  558.   in_job = 1;
  559.   parse_state = NORMAL;
  560.   ignore_input = 0;
  561.   if (signal(SIGINT, set_interrupt_flag) == BADSIG)
  562.     sys_error("signal");
  563.   while ((c = getchar()) != EOF)
  564.     output_char(c);
  565.   flush_output();
  566.   c = '\004';
  567.   blocking_write(&c, 1);
  568.   ec = eof_count;
  569.   while (ec == eof_count)
  570.     process_some_input();
  571. }
  572.  
  573. void get_status()
  574. {
  575.   char c = '\024';
  576.   if (signal(SIGALRM, set_timeout_flag) == BADSIG)
  577.     sys_error("signal");
  578.   ioflush();
  579.   (void)alarm(5);
  580.   blocking_write(&c, 1);
  581.   in_job = 0;
  582.   parse_state = NORMAL;
  583.   ignore_input = 0;
  584.   while (status == INVALID)
  585.     process_some_input();
  586.   switch (status) {
  587.   case IDLE:
  588.     break;
  589.   case WAITING:
  590.     c = '\004';
  591.     blocking_write(&c, 1);
  592.     sleep(5);
  593.     exit(EXIT_REPRINT);
  594.   case BUSY:
  595.   case UNKNOWN:
  596.     sleep(15);
  597.     exit(EXIT_REPRINT);
  598.   }
  599.   if (signal(SIGALRM, SIG_IGN) == BADSIG)
  600.     sys_error("signal");
  601. }
  602.  
  603. void usage()
  604. {
  605.   syslog(LOG_ERR, "usage");
  606.   exit(EXIT_THROW_AWAY);
  607. }
  608.  
  609. int main(argc, argv)
  610. int argc;
  611. char **argv;
  612. {
  613.   int i = 1;
  614.   openlog("lprps", LOG_PID, LOG_LPR);
  615.   while (i < argc && argv[i][0] == '-') {
  616.     switch (argv[i][1]) {
  617.     case 'c':
  618.       break;
  619.     case 'x':
  620.     case 'y':
  621.     case 'w':
  622.     case 'l':
  623.     case 'i':
  624.       break;
  625.     case 'n':
  626.       if (++i == argc)
  627.     usage();
  628.       else
  629.     login = argv[i];
  630.       break;
  631.     case 'h':
  632.       if (++i == argc)
  633.     usage();
  634.       else
  635.     host = argv[i];
  636.  
  637.       break;
  638.     default:
  639.       usage();
  640.     }
  641.     ++i;
  642.   }
  643.   if (i < argc)
  644.     accounting_file = argv[i];
  645.   psfd = 1;
  646.   get_status();
  647.   get_start_pagecount();
  648.   send_file();
  649.   get_end_pagecount();
  650.   do_accounting();
  651.   do_exit(EXIT_SUCCESS);
  652. }
  653.  
  654.