home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / port-lpr / part01 / lpr.c < prev    next >
C/C++ Source or Header  |  1993-04-09  |  25KB  |  1,072 lines

  1. /*
  2.  * "lpr" program for systems that don't have lpd but can talk to a system
  3.  * that does using TCP or DECnet
  4.  *
  5.  * Copyright (C) 1990, 1991 Keith Moore
  6.  
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License, Version 1,
  9.  * as published by the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * Written by Keith Moore, December 1990
  21.  * Email: moore@cs.utk.edu (Internet)    moore@utkvx (BITNET)
  22.  * Snail: Box 16320 / Knoxville TN  37996 / USA
  23.  */
  24.  
  25. /* TO DO:
  26.  * - send troff font names
  27.  * - add support for /etc/printcap files.
  28.  * - special hacks for Imagen and/or PostScript printers (maybe)
  29.  * - support -i (indent) and -w (page width) options
  30.  * - handle huge files too big to read into memory (UNIX systems only)
  31.  * - recognize ditroff, raster, cifplot, and FORTRAN output files (maybe)
  32.  * - handle multiple lpd servers -- try each until we find one that's up.
  33.  * - allow printer names of the form printer@host or host::printer,
  34.  * - add an option to specify job-id (for use when using this program
  35.  *   as the back-end to another print spooling system -- you can keep the
  36.  *   job-ids the same on both systems if you're lucky).
  37.  * - add an option to wait until the job is actually printed -- this is
  38.  *   not easy to do but is very useful when this program is being used
  39.  *   as the back-end to another kind of print spooler.
  40.  */
  41.  
  42. /*
  43.  * #define MAIN_PROGRAM here so common.h will allocate storage for the
  44.  * variables defined there instead of making them external references.
  45.  */
  46.  
  47. #define MAIN_PROGRAM
  48. #include "config.h"
  49. #include "common.h"
  50. #include "patchlevel.h"
  51. #include <stdio.h>
  52. #include <ctype.h>
  53.  
  54. #ifdef unix
  55. #include <sys/types.h>
  56. #include <sys/stat.h>
  57. #define EXIT_OK 0
  58. #define EXIT_FAIL 1
  59. #endif
  60.  
  61. #ifdef vms
  62. #include <types.h>
  63. #include <stat.h>
  64. #define EXIT_OK 0
  65. #define EXIT_FAIL 2
  66. #endif
  67.  
  68. #define VERSION 1
  69.  
  70. /*
  71.  * options...not all of which are supported
  72.  */
  73. char *printer;            /* name of remote print queue */
  74. char *lpd_server;        /* name of the remote printer server */
  75. char file_type = '?';        /* kind of file to be printed */
  76. char *title = NULL;        /* page headings for pr */
  77. char *jobtitle = NULL;        /* job name */
  78. char *jobclass = NULL;        /* job class */
  79. int num_copies = 1;        /* number of copies to print */
  80. int indent = 0;            /* # of spaces to indent */
  81. int page_width = 72;        /* page width for pr */
  82. char *fontnames[4];        /* names of troff fonts */
  83. int lflag = 0;            /* if lpq, list in long format */
  84. int rflag = 0;            /* if 1, remove file after spooling */
  85. int mflag = 0;            /* if 1, send mail on completion */
  86. int hflag = 0;            /* if 1, omit burst page */
  87.  
  88. /* debug option flag is declared in common.h */
  89.  
  90. #define min(a,b) ((a) < (b) ? (a) : (b))
  91. char *getenv ();
  92. char *calloc ();
  93. char *realloc ();
  94. char *strrchr ();
  95.  
  96. /*
  97.  * debugging routines
  98.  */
  99.  
  100. void
  101. dump_buf (fp, prefix, buf, size)
  102. FILE *fp; char *prefix; char *buf; unsigned size;
  103. {
  104.     if (size > 0)
  105.     fprintf (fp, "%s", prefix);
  106.     while (size > 0){
  107.         if (*buf >= ' ' && *buf <= '~')
  108.             putc (*buf, fp);
  109.         else if (*buf == '\n') {
  110.             fprintf (fp, "\\n");
  111.         if (size > 1)
  112.         fprintf (fp, "\n%*s", strlen (prefix), "");
  113.     }
  114.     else
  115.             fprintf (fp, "\\%03o", *buf & 0xff);
  116.         ++buf;
  117.         --size;
  118.     }
  119.     fprintf (fp, "\n");
  120. }
  121.  
  122.  
  123. int
  124. x_read (fd, buf, size)
  125. int fd; char *buf; unsigned size;
  126. {
  127.     int nread = read (fd, (char *) buf, size);
  128.     if (debug)
  129.     dump_buf (stderr, "<<<", buf, nread);
  130.     return nread;
  131. }
  132.  
  133. int
  134. x_write (fd, buf, size)
  135. int fd; char *buf; unsigned size;
  136. {
  137.     if (debug)
  138.     dump_buf (stderr, ">>>", buf, size);
  139.     return write (fd, (char *) buf, size);
  140. }
  141.  
  142. int
  143. y_write (fd, buf, size)
  144. int fd; char *buf; unsigned size;
  145. {
  146.     if (debug)
  147.     fprintf (stderr, ">>> (%d bytes)\n", size);
  148.     return write (fd, (char *) buf, size);
  149. }
  150.  
  151.  
  152. /*
  153.  * parse an option with an optional argument (which may be NULL)
  154.  * return 1 if optional argument used, else 0
  155.  * (one of these days I'll start using getopt())
  156.  */
  157. int
  158. real_option (opt, arg)
  159. char *opt; char *arg;
  160. {
  161.     if (opt[1] && opt[2] == '\0') {
  162.     /* single letter options */
  163.     switch (opt[1]) {
  164.         /*
  165.          * file types
  166.          */
  167.     case 'l':        /* text file with embedded control chars */
  168.         file_type = 'l';
  169.         lflag++;        /* or -l (long) option for lpq */
  170.         return 0;
  171.     case 'f':        /* Fortran output file with carraige control */
  172.         file_type = 'r';
  173.         return 0;
  174.     case 'c':        /* cifplot (Caltech Intermediate Form) file */
  175.     case 'd':        /* TeX .dvi file */
  176.     case 'g':        /* UNIX plot file */
  177.     case 'n':        /* ditroff output file */
  178.     case 'o':        /* PostScript file ??? */
  179.     case 'p':        /* text file (add page headers using pr) */
  180.     case 't':        /* C/A/T troff output file*/
  181.     case 'v':        /* Versatec output file */
  182.         file_type = opt[1];
  183.         return 0;
  184.         /*
  185.          * job options
  186.          */
  187.     case 'P':        /* -P printer */
  188.     case 'q':        /* -q queue (same thing) */
  189.         printer = arg;
  190.         return 1;
  191.     case 'S':        /* specify name of printer server */
  192.         lpd_server = arg;
  193.         return 1;
  194.     case '#':        /* num copies */
  195.         if (arg && isdigit (*arg)) {
  196.         num_copies = atoi (arg);
  197.         return 1;
  198.         }
  199.         break;
  200.     case 'C':        /* job class (default: local hostname) */
  201.         jobclass = arg;
  202.         return 1;
  203.     case 'J':        /* job title (default: first file name) */
  204.         jobtitle = arg;
  205.         return 1;
  206.     case 'i':        /* indent output (default: 8 chars) */
  207.         if (arg && isdigit (*arg)) {
  208.         indent = atoi (arg);
  209.         return 1;
  210.         }
  211.         else {
  212.         indent = 8;
  213.         return 0;
  214.         }
  215.     case '1':        /* troff font names */
  216.     case '2':
  217.     case '3':
  218.     case '4':
  219.         fontnames[opt[1]-'1']=arg;
  220.         return 1;
  221.     case 'w':        /* cols -- page width for pr */
  222.         if (arg && isdigit (*arg)) {
  223.         page_width = atoi (arg);
  224.         return 1;
  225.         }
  226.     case 'r':        /* remove file after spooling */
  227.         rflag = 1;
  228.         return 0;
  229.     case 'm':        /* send mail upon completion */
  230.         mflag = 1;
  231.         return 0;
  232.     case 'h':        /* don't print the burst page */
  233.         hflag = 1;
  234.         return 0;
  235.     case 's':        /* don't copy file -- symlink it */
  236.         fprintf (stderr,
  237.              "lpr: The -s (symlink) option is not supported\n");
  238.         fprintf (stderr,
  239.              "All files will be copied to the remote server\n");
  240.         return 0;
  241.     }
  242.     }
  243.     if (strcmp (opt, "-debug") == 0) {
  244.     debug = 1;
  245.     fprintf (stderr, "standalone lpr version %d.%d\n",
  246.          VERSION, PATCHLEVEL);
  247.     return 0;
  248.     }
  249.     fprintf (stderr, "lpr: warning: illegal option %s\n", opt);
  250.     return 0;
  251. }
  252.  
  253. int
  254. option (opt, optarg)
  255. char *opt; char *optarg;
  256. {
  257.     /*
  258.      * This hack is used to notice whether the argument for an option
  259.      * is appended to the option itself (e.g. "-Pprinter" rather than
  260.      * "-P" "printer".  If this is the case, and the option accepts an
  261.      * argument, split the arg into two args and call real_option().
  262.      * otherwise just pass our args to real_option().
  263.      */
  264.   
  265.     if (opt[2] && strchr ("SP#CJTi1234qw", opt[1])) {
  266.     char temp[3];
  267.     temp[0] = '-';
  268.     temp[1] = opt[1];
  269.     temp[2] = '\0';
  270.     real_option (temp, opt + 2);
  271.     return 0;
  272.     }
  273.     else
  274.     return real_option (opt, optarg);
  275. }
  276.  
  277. /*
  278.  * keep up with files to be deleted (for when using -r)
  279.  * This is so we don't delete files until we *know* that the job
  280.  * has been successfully submitted.
  281.  */
  282.  
  283. struct delete_list {
  284.     char *name;
  285.     struct delete_list *next;
  286. } *head = NULL;
  287.  
  288. void
  289. mark_for_delete (name)
  290. char *name;
  291. {
  292.     struct delete_list *ptr = (struct delete_list *)
  293.     calloc (1, sizeof (struct delete_list));
  294.     if (!ptr) {
  295.     perror ("calloc");
  296.     return;
  297.     }
  298.     ptr->next = head;
  299.     ptr->name = name;
  300.     head = ptr;
  301. }
  302.  
  303. void
  304. delete_marked_files ()
  305. {
  306.     struct delete_list *ptr;
  307.     for (ptr = head; ptr; ptr=ptr->next) {
  308.     if (ptr->name)
  309.         if (unlink (ptr->name) < 0) {
  310.         fprintf (stderr, "lpr: could not delete %s\n", ptr->name);
  311.         perror ("unlink");
  312.         }
  313.     }
  314. }
  315.  
  316. /*
  317.  * buffer management
  318.  */
  319. struct buffer {
  320.     char *ptr;            /* points to current append point */
  321.     int size;            /* how big is the buffer now? */
  322.     char text[1];        /* (extensible) array of bytes in the buffer */
  323. };
  324.  
  325. /*
  326.  * Create an empty buffer
  327.  */
  328.  
  329. struct buffer *
  330. create_buffer (initial_size)
  331. unsigned int initial_size;
  332. {
  333.     struct buffer *buf;
  334.  
  335.     if (initial_size <= 0)
  336.     initial_size = 1000;
  337.     if ((buf = (struct buffer *)
  338.      calloc (1, sizeof (struct buffer) + initial_size - 1)) == NULL)
  339.     return NULL;
  340.     buf->ptr = &(buf->text[0]);
  341.     buf->size = initial_size;
  342.     return buf;
  343. }
  344.  
  345. /*
  346.  * Ensure there is enough room in the buffer for "more" more bytes
  347.  */
  348. struct buffer *
  349. enlarge_buffer (buf, more)
  350. struct buffer *buf;
  351. int more;
  352. {
  353.     int offset = buf->ptr - &(buf->text[0]);
  354.     int spaceleft = buf->size - offset;
  355.  
  356.     if (more > spaceleft) {
  357.     int newsize = sizeof (struct buffer) + (buf->size * 2) - 1;
  358.     buf = (struct buffer *) realloc ((char *) buf, newsize);
  359.     if (buf == NULL) {
  360.         perror ("enlarge_buffer(): realloc failed");
  361.         return NULL;
  362.     }
  363.     buf->ptr = &(buf->text[0]) + offset;
  364.     buf->size = newsize;
  365.     }
  366.     return buf;
  367. }
  368.  
  369. /*
  370.  * Append up to max_size bytes from an open file to buffer
  371.  */
  372.  
  373. struct buffer *
  374. read_file_into_buffer (buf, fd, max_size)
  375. struct buffer *buf;
  376. int fd;
  377. unsigned max_size;
  378. {
  379.     int real_size = 0;
  380.  
  381.     while (max_size > 0)  {
  382.     int foo = min (max_size, max_net_read);
  383.     if ((buf = enlarge_buffer (buf, foo)) == NULL)
  384.         return NULL;
  385.     if ((foo = read (fd, buf->ptr, foo)) < 0)
  386.         return NULL;
  387.     if (foo == 0)
  388.         break;
  389.     buf->ptr += foo;
  390.     max_size -= foo;
  391.     real_size += foo;
  392.     }
  393.     return buf;
  394. }
  395.  
  396. /*
  397.  * Append a NUL-terminated string to the buffer
  398.  */
  399.  
  400. struct buffer *
  401. append_string_to_buffer (buf, string, length)
  402. struct buffer *buf;
  403. char *string;
  404. int length;
  405. {
  406.     if ((buf = enlarge_buffer (buf, length)) == NULL) {
  407.     fprintf (stderr, "lpr: file too big to fit in memory\n");
  408.     exit (EXIT_FAIL);
  409.     }
  410.     strncpy (buf->ptr, string, length);
  411.     buf->ptr += length;
  412.     return buf;
  413. }
  414.  
  415. /*
  416.  * Write out the entire contents of buffer to the file fd.
  417.  */
  418.  
  419. int
  420. send_file_from_buffer (fd, buf)
  421. int fd; struct buffer *buf;
  422. {
  423.     char *wptr = buf->text;
  424.     while (wptr < buf->ptr) {
  425.     unsigned int foo = min (buf->ptr - wptr, max_net_write);
  426.     if ((foo = y_write (fd, wptr, foo)) < 0)
  427.         return EOF;
  428.     wptr += foo;
  429.     }
  430.     return 0;
  431. }
  432.  
  433. /*
  434.  * free up a buffer
  435.  */
  436.  
  437. void
  438. free_buffer (buf)
  439. struct buffer *buf;
  440. {
  441.     if (buf)
  442.     cfree (buf);
  443. }
  444.  
  445. int
  446. buffer_size (buf)
  447. struct buffer *buf;
  448. {
  449.     if (buf)
  450.     return (buf->ptr - buf->text);
  451.     return EOF;
  452. }
  453.  
  454. /*
  455.  * Look at a file buffer and guess what kind of file it is.  This is called
  456.  * when we aren't given an explicit file type option.
  457.  */
  458.  
  459. char
  460. guess_file_type (buf, fname)
  461. struct buffer *buf; char *fname;
  462. {
  463.     char *ptr = buf->text;
  464.     if (ptr[0] == '%' && ptr[1] == '!')
  465.     return 'f';        /* print PostScript as plain file */
  466.     if (ptr[0] == '\367' && ptr[1] == 2) {
  467.     fprintf (stderr, "lpr: %s is a TeX .dvi file, assuming -d\n", fname);
  468.     return 'd';        /* TeX .dvi file */
  469.     }
  470.     if (ptr[0] == '\100' && ptr[1] == '\357')  {
  471.     fprintf (stderr, "lpr: %s is a C/A/T troff output file, assuming -t\n",
  472.          fname);
  473.     return 't';        /* C/A/T troff file */
  474.     }
  475.     return 'f';            /* default file type is plain file */
  476. }
  477.  
  478. int
  479. check_for_bogus_file (buf, type, filename)
  480. struct buffer *buf; char type; char *filename;
  481. {
  482.     char *ptr = buf->text;
  483.  
  484.     if (buf->ptr == buf->text) {
  485.     fprintf (stderr, "lpr: skipping zero-length file %s\n", filename);
  486.     return EOF;
  487.     }
  488.     
  489.     if (ptr[0] == '\037' && ptr[1] == '\235') {
  490.     fprintf (stderr, "lpr: %s is a compressed file -- ignoring it\n",
  491.          filename);
  492.     return EOF;
  493.     }
  494.     if (type == 'd') {
  495.     if (ptr[0] == '\367' && ptr[1] == '\002') {
  496.         /* sometimes .dvi files have trailing NULs when they
  497.            shouldn't have.  Remove these from the buffer and
  498.            check that the .dvi file ends with a \337 byte. */
  499.         if (buf->ptr[-1] == '\0') {
  500.         while (buf->ptr[-1] == '\0')
  501.             --(buf->ptr);
  502.         }
  503.         if (buf->ptr[-1] == '\337')
  504.         return 0;
  505.     }
  506.     fprintf (stderr, "lpr: %s is not a valid .dvi file", filename);
  507.     return EOF;
  508.     }
  509.     if (memcmp (ptr, "!<arch>\n", 8) == 0) {
  510.     fprintf (stderr, "lpr: %s is a UNIX library archive -- ignoring it",
  511.          filename);
  512.     return EOF;
  513.     }
  514.     return 0;
  515. }
  516.  
  517.  
  518. /*
  519.  * Send a command to the remote server and wait for a response.  Return
  520.  * the first byte of the response, or EOF on error.
  521.  */
  522.  
  523. int
  524. send_command (fd, buf, size)
  525. int fd; char *buf; unsigned int size;
  526. {
  527.     char x[1];
  528.     if (x_write (fd, buf, size) != size)
  529.     return EOF;
  530.     if (x_read (fd, x, 1) != 1)
  531.     return EOF;
  532.     return *x;
  533. }
  534.  
  535.  
  536. /*
  537.  * structure used to keep track of print jobs
  538.  */
  539. struct job {
  540.     int jobid;            /* integer job id 1-999 */
  541.     int fd;            /* fd of lpd socket */
  542.     int control_file_number;    /* current file number */
  543.     int data_file_number;    /* data_file_number */
  544.     struct buffer *cfile;    /* buffer to build control file */
  545. };
  546.  
  547. /*
  548.  * add a record to a control file
  549.  */
  550. void
  551. control (job, cmd, arg)
  552. struct job *job; char cmd; char *arg;
  553. {
  554.     char buf[512];
  555.     sprintf (buf, "%c%s\n", cmd, arg);
  556.     job->cfile = append_string_to_buffer (job->cfile, buf, strlen (buf));
  557. }
  558.  
  559.  
  560. /*
  561.  * create a print job.  Return a job ptr on success or NULL on error.
  562.  */
  563. struct job *
  564. open_job (queuename)
  565. char *queuename;
  566. {
  567.     struct job *job;
  568.     char buf[512];
  569.     char x;
  570.  
  571.     if ((job = (struct job *) calloc (1, sizeof (struct job))) == NULL)
  572.     return NULL;
  573.     /*
  574.      * generate a job #.  Really, this should be maintained on a
  575.      * per-(host,queue) basis, so we won't have naming conflicts.
  576.      * for now, we just generate something pseudo-random.
  577.      */
  578.     job->jobid = time (0) % 1000;
  579.     job->fd = open_lpd (lpd_server);
  580.     if (job->fd  < 0) {
  581.     free (job);
  582.     return NULL;
  583.     }
  584.  
  585.     sprintf (buf, "\2%s\n", queuename);
  586.     if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
  587.     if (isprint (x)) {
  588.         int foo;
  589.         *buf = x;
  590.         foo = x_read (job->fd, buf+1, sizeof(buf)-1);
  591.         fprintf (stderr,
  592.              "lpr: server %s refused job with message:\n",
  593.              lpd_server);
  594.         fprintf (stderr, "%.*s", foo+1, buf);
  595.     }
  596.     else {
  597.         fprintf (stderr,
  598.              "lpr: server %s refused job for printer %s\n",
  599.              lpd_server, queuename);
  600.     }
  601.     close (job->fd);
  602.     free (job);
  603.     return NULL;
  604.     }
  605.  
  606.     job->control_file_number = 0;
  607.     job->data_file_number = 0;
  608.     job->cfile = create_buffer (1000);
  609.  
  610.     control (job, 'H', hostname);
  611.     control (job, 'P', username);
  612.     if (hflag == 0) {
  613.     control (job, 'J', jobtitle);
  614.     control (job, 'C', jobclass);
  615.     }
  616.     control (job, 'L', username);
  617.     if (title)
  618.     control (job, 'T', title);
  619.     if (mflag)
  620.     control (job, 'M', email_address);
  621.     return job;
  622. }
  623.  
  624. void
  625. concoct_file_name (c, job, str)
  626. char c; struct job *job; char *str;
  627. {
  628.     int x = c == 'd' ? job->data_file_number++ : job->control_file_number++;
  629.     sprintf (str, "%cf%c%03d%s", c,
  630.          "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[x],
  631.          job->jobid, hostname);
  632. }
  633.  
  634. /*
  635.  * Send a file to be printed.  Return 1 on success and 0 on error.
  636.  * (i.e. # of files sent). 
  637.  * print diagnostic messages to stderr as necessary
  638.  * If file == NULL, print standard input
  639.  */
  640. int
  641. send_print_file (job, file, file_type)
  642. struct job *job; char *file; char file_type;
  643. {
  644.     int estimated_size;        /* how big we think the file is */
  645.     int max_size;        /* max size to print */
  646.     int real_size;
  647.     int fd = EOF;        /* fd of file */
  648.     struct buffer *dfile = NULL; /* buffer to read file into */
  649.     char *reason = NULL;    /* reason file xfer failed */
  650.     char data_file_name[512];    /* name of temporary data file */
  651.     char buf[512];
  652.     int x;
  653.     int i;
  654.  
  655.     /*
  656.      * open the file and find out how big it is
  657.      * estimated_size is used to determine how much space to allocate.
  658.      * max_size is used to decide how much to read in.  Under VMS
  659.      * we don't ever want to read too much, because we might get
  660.      * unwanted garbage at the end of a fixed-length record file.
  661.      */
  662.     if (file) {
  663.     struct stat sbuf;    
  664.     if (stat (file, &sbuf) < 0) {
  665.         perror (file);
  666.         return 0;
  667.     }
  668.     max_size = estimated_size = sbuf.st_size;
  669.     if ((fd = open (file, 0)) < 0) {
  670.         perror (file);
  671.         return 0;
  672.     }
  673.     }
  674.     else {
  675.     struct stat sbuf;
  676.     file = "standard input"; /* for page headers, error messages */
  677.     estimated_size = 64000;
  678.     max_size = 5*1024*1024;    /* 5 megabytes */
  679.     fd = 0;
  680. #ifdef unix
  681.     /*
  682.      * UNIX-specific performance optimization:
  683.      * If standard input is an ordinary file, get size estimate
  684.      * with fstat()
  685.      */
  686.     if (fstat (fd, &sbuf) < 0) {
  687.         if ((sbuf.st_mode & S_IFMT) == S_IFREG)
  688.         estimated_size = sbuf.st_size;
  689.     }
  690. #endif
  691.     }
  692.  
  693.     /*
  694.      * create a buffer and read the file into it.
  695.      */
  696.     concoct_file_name ('d', job, data_file_name);
  697.     if ((dfile = create_buffer (estimated_size)) == NULL) {
  698.         reason = "file too big to fit in memory";
  699.     goto abort;
  700.     }
  701.     if ((dfile = read_file_into_buffer (dfile, fd, max_size)) == NULL) {
  702.     reason = "error reading file";
  703.     goto abort;
  704.     }
  705.  
  706.     /*
  707.      * file transfer successful.  Add this file to the print job,
  708.      * clean up, and return.
  709.      */
  710.     if (file_type == '?')
  711.     file_type = guess_file_type (dfile, file);
  712.     /*
  713.      * check for bogus file formats.  Refuse to print anything that
  714.      * is obviously bogus.
  715.      */
  716.     if (check_for_bogus_file (dfile, file_type, file))
  717.     goto okay;
  718.  
  719.     /*
  720.      * transfer the file to the server, with error checking
  721.      */
  722.     sprintf (buf, "\3%d %s\n", buffer_size(dfile), data_file_name);
  723.     if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
  724.     switch (x) {
  725.     case 1:
  726.         break;
  727.     case 2:
  728.         reason = "not enough disk space on server (or file is too large)";
  729.         break;
  730.     case EOF:
  731.         reason = "connection to printer server broken";
  732.         break;
  733.     default:
  734.         if (isprint (x)) {
  735.         *buf = x;
  736.         x = x_read (job->fd, buf + 1, sizeof (buf) - 1);
  737.         buf[x+1] = '\0';
  738.         reason = buf;
  739.         }
  740.     }
  741.     goto abort;
  742.     }
  743.     if (send_file_from_buffer (job->fd, dfile) != 0)
  744.     goto abort;
  745.     if (send_command (job->fd, "", 1) < 0)
  746.     goto abort;
  747.  
  748.     if (file_type == 'p' && !title)
  749.     control (job, 'P', file);
  750.     for (i = 0; i < num_copies; ++i)
  751.     control (job, file_type, data_file_name);
  752.     control (job, 'U', data_file_name);
  753.     control (job, 'N', file);
  754.  okay:
  755.     free_buffer (dfile);
  756.     close (fd);
  757.     return 1;
  758.  
  759.  
  760.     /*
  761.      * file transfer failed.  print error message and clean up
  762.      */
  763.  abort:
  764.     fprintf (stderr, "lpr: unable to send file %s to print server %s\n",
  765.          file, lpd_server);
  766.     if (reason)
  767.     fprintf (stderr, "reason: %s\n", reason);
  768.     if (dfile)
  769.     free_buffer (dfile);
  770.     if (fd > 0)
  771.     close (fd);
  772.     return 0;
  773. }
  774.  
  775. /*
  776.  * send the control file.  Return 0 on success, nonzero on error.
  777.  */
  778. send_control_file (job)
  779. struct job *job;
  780. {
  781.     char buf[512];
  782.     char control_file_name[512];
  783.  
  784.     concoct_file_name ('c', job, control_file_name);
  785.     sprintf (buf, "\2%d %s\n", job->cfile->ptr - job->cfile->text,
  786.          control_file_name);
  787.     if (send_command (job->fd, buf, strlen (buf)) < 0)
  788.     return 1;
  789.     if (send_file_from_buffer (job->fd, job->cfile) != 0)
  790.     return 1;
  791.     if (send_command (job->fd, "", 1) < 0)
  792.     return 1;
  793.     return 0;
  794. }
  795.  
  796. /*
  797.  * close a job normally and delete its resources
  798.  */
  799. int
  800. close_job (job)
  801. struct job *job;
  802. {
  803.     int x;
  804.     if (job == NULL)
  805.     return EOF;
  806.     x = send_control_file (job);
  807.     if (job->cfile)
  808.     free_buffer (job->cfile);
  809.     close (job->fd);
  810.     cfree (job);
  811.     return x;
  812. }
  813.  
  814. /*
  815.  * abort a job and delete its resources
  816.  */
  817. void
  818. abort_job (job)
  819. struct job *job;
  820. {
  821.     if (job == NULL)
  822.     return;
  823.     x_write (job->fd, "\1\n", 2);
  824.     close (job->fd);
  825.     if (job->cfile)
  826.     free_buffer (job->cfile);
  827.     cfree (job);
  828. }
  829.  
  830.  
  831. char *
  832. get_lpd_server ()
  833. {
  834.     FILE *fp;
  835.     static char *buf[512];
  836.     
  837.     if ((fp = fopen ("/etc/LPD_SERVER", "r")) == (FILE *) NULL)
  838.     return NULL;
  839.     if (fscanf (fp, " %511s", buf) != 1)
  840.     return NULL;
  841.     return (char *) buf;
  842. }
  843.  
  844.  
  845. /*
  846.  * Dummy main program exists to find out what name we are being called
  847.  * by (under UNIX, anyway) and act appropriately.  This program has
  848.  * multiple personalities...
  849.  */
  850.  
  851. main (argc, argv)
  852. int argc; char **argv;
  853. {
  854. #ifdef unix
  855.     char *progname = NULL;
  856.     char *strrchr ();
  857. #endif
  858.     char *p;
  859.  
  860.     /*
  861.      * inherit some defaults from the environment
  862.      */
  863.  
  864.     printer = getenv ("PRINTER");
  865.     if (printer == NULL)
  866.     printer = "lp";
  867.     lpd_server = getenv ("LPD_SERVER");
  868.     if (lpd_server == NULL)
  869.     lpd_server = get_lpd_server ();
  870.  
  871.     sysdep ();
  872.  
  873. #ifdef unix
  874.     /*
  875.      * look at the last component of the name we were invoked with
  876.      * and determine how to behave.
  877.      */
  878.     progname = strrchr (argv[0], '/');
  879.     if (progname == NULL)
  880.     progname = argv[0];
  881.     else
  882.     progname++;
  883.  
  884.     if (strcmp (progname, "lpq") == 0)
  885.     return (lpq (argc, argv));
  886.     else if (strcmp (progname, "lprm") == 0)
  887.     return (lprm (argc, argv));
  888. #endif
  889.  
  890.     /*
  891.      * if first argument is -remove or -delete, behave as lprm
  892.      * if first argumetn is -showqueue, behave as lpq
  893.      */
  894.  
  895.     if (argc > 1) {
  896.     if (strcmp (argv[1], "-remove") == 0)
  897.         return (lprm (argc-1, argv+1));
  898.     else if (strcmp (argv[1], "-delete") == 0)
  899.         return (lprm (argc-1, argv+1));
  900.     else if (strcmp (argv[1], "-showqueue") == 0)
  901.         return (lpq (argc-1, argv+1));
  902.     }
  903.  
  904.     return (lpr (argc, argv));
  905. }
  906.  
  907. /*
  908.  * queue one or more files for printing
  909.  */
  910.  
  911. lpr (argc, argv)
  912. int argc; char **argv;
  913. {
  914.     struct job *job = NULL;
  915.     int i;
  916.     int file_args = 0;
  917.     int files_printed = 0;
  918.  
  919.     jobclass = hostname;
  920.     jobtitle = NULL;
  921.  
  922.     for (i = 1; i < argc; ++i) {
  923.     if (*argv[i] == '-')
  924.         i += option (argv[i], argv[i+1]);
  925.     else {
  926.         if (!jobtitle) {
  927.         char *ptr = strrchr (argv[i], '/');
  928.         jobtitle = ptr ? ptr + 1 : argv[i];
  929.         }
  930.         if (job == NULL && (job = open_job (printer)) == NULL)
  931.         exit (EXIT_FAIL);
  932.         file_args++;
  933.         if (send_print_file (job, argv[i], file_type)) {
  934.         files_printed++;
  935.         if (rflag)
  936.             mark_for_delete (argv[i]);
  937.         }
  938.     }
  939.     }
  940.     if (file_args == 0) {
  941.     if (!jobtitle)
  942.         jobtitle = "stdin";
  943.     if ((job = open_job (printer)) == NULL)
  944.         exit (EXIT_FAIL);
  945.     files_printed += send_print_file (job, 0, file_type);
  946.     }
  947.     if (files_printed > 0) {
  948.     if (close_job (job)) {
  949.         delete_marked_files ();
  950.         exit (EXIT_OK);
  951.     }
  952.     else
  953.         exit (EXIT_FAIL);
  954.     }
  955.     else
  956.     exit (EXIT_FAIL);
  957.     exit (EXIT_OK);
  958. }
  959.  
  960. /*
  961.  * print contents of printer queue
  962.  * "lpq -l" prints in long format
  963.  */
  964.  
  965. lpq (argc, argv)
  966. int argc; char **argv;
  967. {
  968.     int i;
  969.     char buf[512];
  970.     int fd;
  971.     int x;
  972.  
  973.     for (i = 1; i < argc ; ++i) {
  974.     if (*argv[i] == '-')
  975.         i += option (argv[i], argv[i+1]);
  976.     else
  977.         break;
  978.     }
  979.  
  980.     if ((fd = open_lpd (lpd_server)) < 0)
  981.     exit (EXIT_FAIL);
  982.  
  983.     if (lflag)
  984.     sprintf (buf, "\004%s", printer);
  985.     else
  986.     sprintf (buf, "\003%s", printer);
  987.  
  988.     for (; i < argc; ++i) {
  989.     strcat (buf, " ");
  990.     strcat (buf, argv[i]);
  991.     }
  992.  
  993.     strcat (buf, "\n");
  994.     if (x_write (fd, buf, strlen (buf)) != 0) {
  995.     while ((x = x_read (fd, buf, sizeof buf)) > 0)
  996.         fwrite (buf, sizeof (char), x, stdout);
  997.     }
  998.     close (fd);
  999.     return 0;
  1000. }
  1001.  
  1002. /*
  1003.  * remove jobs from queue
  1004.  */
  1005.  
  1006. lprm (argc, argv)
  1007. int argc; char **argv;
  1008. {
  1009.     int fd;
  1010.     int i;
  1011.     char buf[512];
  1012.     int x;
  1013.     int response_length = 0;
  1014.     int remove_all = 0;
  1015.  
  1016.     for (i = 1; i < argc; ++i) {
  1017.     if (strcmp (argv[i], "-") == 0)
  1018.         remove_all++;
  1019.     else if (*argv[i] == '-')
  1020.         i += option (argv[i], argv[i+1]);
  1021.     else
  1022.         break;
  1023.     }
  1024.  
  1025.     if ((fd = open_lpd (lpd_server)) < 0)
  1026.     exit (EXIT_FAIL);
  1027.  
  1028.     /*
  1029.      * If user asks to remove all queued files with "lprm -",
  1030.      * need to check to see if user is privileged to do so.
  1031.      * Allow root to remove all queued files, but any other
  1032.      * user will just remove his/her own queued files.
  1033.      * (remote server will only delete files queued by this system)
  1034.      *
  1035.      * "-all" is a magic user name which means delete all
  1036.      * entries from this system.
  1037.      */
  1038.     if (remove_all) {
  1039. #ifdef unix
  1040.     if (strcmp (username, "root") == 0)
  1041.         sprintf (buf, "\005%s %s", printer, "-all");
  1042.     else
  1043.         sprintf (buf, "\005%s %s %s", printer, username, username);
  1044. #else
  1045.     sprintf (buf, "\005%s %s %s", printer, username, username);
  1046. #endif
  1047.     }
  1048.     else {
  1049.     sprintf (buf, "\005%s %s", printer, username);
  1050.     }
  1051.  
  1052.     for (; i < argc; ++i) {
  1053.     strcat (buf, " ");
  1054.     strcat (buf, argv[i]);
  1055.     }
  1056.     strcat (buf, "\n");
  1057.     if (x_write (fd, buf, strlen (buf)) != 0) {
  1058.     while ((x = x_read (fd, buf, sizeof buf)) > 0) {
  1059.         fwrite (buf, sizeof (char), x, stdout);
  1060.         response_length += x;
  1061.     }
  1062.     }
  1063.     close (fd);
  1064.  
  1065.     /* If response_length is zero, assume the remove command failed.
  1066.        Otherwise we should have received some confirmation message */
  1067.  
  1068.     if (response_length == 0)
  1069.     return 1;
  1070.     return 0;
  1071. }
  1072.