home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume26
/
port-lpr
/
part01
/
lpr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-09
|
25KB
|
1,072 lines
/*
* "lpr" program for systems that don't have lpd but can talk to a system
* that does using TCP or DECnet
*
* Copyright (C) 1990, 1991 Keith Moore
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, Version 1,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Written by Keith Moore, December 1990
* Email: moore@cs.utk.edu (Internet) moore@utkvx (BITNET)
* Snail: Box 16320 / Knoxville TN 37996 / USA
*/
/* TO DO:
* - send troff font names
* - add support for /etc/printcap files.
* - special hacks for Imagen and/or PostScript printers (maybe)
* - support -i (indent) and -w (page width) options
* - handle huge files too big to read into memory (UNIX systems only)
* - recognize ditroff, raster, cifplot, and FORTRAN output files (maybe)
* - handle multiple lpd servers -- try each until we find one that's up.
* - allow printer names of the form printer@host or host::printer,
* - add an option to specify job-id (for use when using this program
* as the back-end to another print spooling system -- you can keep the
* job-ids the same on both systems if you're lucky).
* - add an option to wait until the job is actually printed -- this is
* not easy to do but is very useful when this program is being used
* as the back-end to another kind of print spooler.
*/
/*
* #define MAIN_PROGRAM here so common.h will allocate storage for the
* variables defined there instead of making them external references.
*/
#define MAIN_PROGRAM
#include "config.h"
#include "common.h"
#include "patchlevel.h"
#include <stdio.h>
#include <ctype.h>
#ifdef unix
#include <sys/types.h>
#include <sys/stat.h>
#define EXIT_OK 0
#define EXIT_FAIL 1
#endif
#ifdef vms
#include <types.h>
#include <stat.h>
#define EXIT_OK 0
#define EXIT_FAIL 2
#endif
#define VERSION 1
/*
* options...not all of which are supported
*/
char *printer; /* name of remote print queue */
char *lpd_server; /* name of the remote printer server */
char file_type = '?'; /* kind of file to be printed */
char *title = NULL; /* page headings for pr */
char *jobtitle = NULL; /* job name */
char *jobclass = NULL; /* job class */
int num_copies = 1; /* number of copies to print */
int indent = 0; /* # of spaces to indent */
int page_width = 72; /* page width for pr */
char *fontnames[4]; /* names of troff fonts */
int lflag = 0; /* if lpq, list in long format */
int rflag = 0; /* if 1, remove file after spooling */
int mflag = 0; /* if 1, send mail on completion */
int hflag = 0; /* if 1, omit burst page */
/* debug option flag is declared in common.h */
#define min(a,b) ((a) < (b) ? (a) : (b))
char *getenv ();
char *calloc ();
char *realloc ();
char *strrchr ();
/*
* debugging routines
*/
void
dump_buf (fp, prefix, buf, size)
FILE *fp; char *prefix; char *buf; unsigned size;
{
if (size > 0)
fprintf (fp, "%s", prefix);
while (size > 0){
if (*buf >= ' ' && *buf <= '~')
putc (*buf, fp);
else if (*buf == '\n') {
fprintf (fp, "\\n");
if (size > 1)
fprintf (fp, "\n%*s", strlen (prefix), "");
}
else
fprintf (fp, "\\%03o", *buf & 0xff);
++buf;
--size;
}
fprintf (fp, "\n");
}
int
x_read (fd, buf, size)
int fd; char *buf; unsigned size;
{
int nread = read (fd, (char *) buf, size);
if (debug)
dump_buf (stderr, "<<<", buf, nread);
return nread;
}
int
x_write (fd, buf, size)
int fd; char *buf; unsigned size;
{
if (debug)
dump_buf (stderr, ">>>", buf, size);
return write (fd, (char *) buf, size);
}
int
y_write (fd, buf, size)
int fd; char *buf; unsigned size;
{
if (debug)
fprintf (stderr, ">>> (%d bytes)\n", size);
return write (fd, (char *) buf, size);
}
/*
* parse an option with an optional argument (which may be NULL)
* return 1 if optional argument used, else 0
* (one of these days I'll start using getopt())
*/
int
real_option (opt, arg)
char *opt; char *arg;
{
if (opt[1] && opt[2] == '\0') {
/* single letter options */
switch (opt[1]) {
/*
* file types
*/
case 'l': /* text file with embedded control chars */
file_type = 'l';
lflag++; /* or -l (long) option for lpq */
return 0;
case 'f': /* Fortran output file with carraige control */
file_type = 'r';
return 0;
case 'c': /* cifplot (Caltech Intermediate Form) file */
case 'd': /* TeX .dvi file */
case 'g': /* UNIX plot file */
case 'n': /* ditroff output file */
case 'o': /* PostScript file ??? */
case 'p': /* text file (add page headers using pr) */
case 't': /* C/A/T troff output file*/
case 'v': /* Versatec output file */
file_type = opt[1];
return 0;
/*
* job options
*/
case 'P': /* -P printer */
case 'q': /* -q queue (same thing) */
printer = arg;
return 1;
case 'S': /* specify name of printer server */
lpd_server = arg;
return 1;
case '#': /* num copies */
if (arg && isdigit (*arg)) {
num_copies = atoi (arg);
return 1;
}
break;
case 'C': /* job class (default: local hostname) */
jobclass = arg;
return 1;
case 'J': /* job title (default: first file name) */
jobtitle = arg;
return 1;
case 'i': /* indent output (default: 8 chars) */
if (arg && isdigit (*arg)) {
indent = atoi (arg);
return 1;
}
else {
indent = 8;
return 0;
}
case '1': /* troff font names */
case '2':
case '3':
case '4':
fontnames[opt[1]-'1']=arg;
return 1;
case 'w': /* cols -- page width for pr */
if (arg && isdigit (*arg)) {
page_width = atoi (arg);
return 1;
}
case 'r': /* remove file after spooling */
rflag = 1;
return 0;
case 'm': /* send mail upon completion */
mflag = 1;
return 0;
case 'h': /* don't print the burst page */
hflag = 1;
return 0;
case 's': /* don't copy file -- symlink it */
fprintf (stderr,
"lpr: The -s (symlink) option is not supported\n");
fprintf (stderr,
"All files will be copied to the remote server\n");
return 0;
}
}
if (strcmp (opt, "-debug") == 0) {
debug = 1;
fprintf (stderr, "standalone lpr version %d.%d\n",
VERSION, PATCHLEVEL);
return 0;
}
fprintf (stderr, "lpr: warning: illegal option %s\n", opt);
return 0;
}
int
option (opt, optarg)
char *opt; char *optarg;
{
/*
* This hack is used to notice whether the argument for an option
* is appended to the option itself (e.g. "-Pprinter" rather than
* "-P" "printer". If this is the case, and the option accepts an
* argument, split the arg into two args and call real_option().
* otherwise just pass our args to real_option().
*/
if (opt[2] && strchr ("SP#CJTi1234qw", opt[1])) {
char temp[3];
temp[0] = '-';
temp[1] = opt[1];
temp[2] = '\0';
real_option (temp, opt + 2);
return 0;
}
else
return real_option (opt, optarg);
}
/*
* keep up with files to be deleted (for when using -r)
* This is so we don't delete files until we *know* that the job
* has been successfully submitted.
*/
struct delete_list {
char *name;
struct delete_list *next;
} *head = NULL;
void
mark_for_delete (name)
char *name;
{
struct delete_list *ptr = (struct delete_list *)
calloc (1, sizeof (struct delete_list));
if (!ptr) {
perror ("calloc");
return;
}
ptr->next = head;
ptr->name = name;
head = ptr;
}
void
delete_marked_files ()
{
struct delete_list *ptr;
for (ptr = head; ptr; ptr=ptr->next) {
if (ptr->name)
if (unlink (ptr->name) < 0) {
fprintf (stderr, "lpr: could not delete %s\n", ptr->name);
perror ("unlink");
}
}
}
/*
* buffer management
*/
struct buffer {
char *ptr; /* points to current append point */
int size; /* how big is the buffer now? */
char text[1]; /* (extensible) array of bytes in the buffer */
};
/*
* Create an empty buffer
*/
struct buffer *
create_buffer (initial_size)
unsigned int initial_size;
{
struct buffer *buf;
if (initial_size <= 0)
initial_size = 1000;
if ((buf = (struct buffer *)
calloc (1, sizeof (struct buffer) + initial_size - 1)) == NULL)
return NULL;
buf->ptr = &(buf->text[0]);
buf->size = initial_size;
return buf;
}
/*
* Ensure there is enough room in the buffer for "more" more bytes
*/
struct buffer *
enlarge_buffer (buf, more)
struct buffer *buf;
int more;
{
int offset = buf->ptr - &(buf->text[0]);
int spaceleft = buf->size - offset;
if (more > spaceleft) {
int newsize = sizeof (struct buffer) + (buf->size * 2) - 1;
buf = (struct buffer *) realloc ((char *) buf, newsize);
if (buf == NULL) {
perror ("enlarge_buffer(): realloc failed");
return NULL;
}
buf->ptr = &(buf->text[0]) + offset;
buf->size = newsize;
}
return buf;
}
/*
* Append up to max_size bytes from an open file to buffer
*/
struct buffer *
read_file_into_buffer (buf, fd, max_size)
struct buffer *buf;
int fd;
unsigned max_size;
{
int real_size = 0;
while (max_size > 0) {
int foo = min (max_size, max_net_read);
if ((buf = enlarge_buffer (buf, foo)) == NULL)
return NULL;
if ((foo = read (fd, buf->ptr, foo)) < 0)
return NULL;
if (foo == 0)
break;
buf->ptr += foo;
max_size -= foo;
real_size += foo;
}
return buf;
}
/*
* Append a NUL-terminated string to the buffer
*/
struct buffer *
append_string_to_buffer (buf, string, length)
struct buffer *buf;
char *string;
int length;
{
if ((buf = enlarge_buffer (buf, length)) == NULL) {
fprintf (stderr, "lpr: file too big to fit in memory\n");
exit (EXIT_FAIL);
}
strncpy (buf->ptr, string, length);
buf->ptr += length;
return buf;
}
/*
* Write out the entire contents of buffer to the file fd.
*/
int
send_file_from_buffer (fd, buf)
int fd; struct buffer *buf;
{
char *wptr = buf->text;
while (wptr < buf->ptr) {
unsigned int foo = min (buf->ptr - wptr, max_net_write);
if ((foo = y_write (fd, wptr, foo)) < 0)
return EOF;
wptr += foo;
}
return 0;
}
/*
* free up a buffer
*/
void
free_buffer (buf)
struct buffer *buf;
{
if (buf)
cfree (buf);
}
int
buffer_size (buf)
struct buffer *buf;
{
if (buf)
return (buf->ptr - buf->text);
return EOF;
}
/*
* Look at a file buffer and guess what kind of file it is. This is called
* when we aren't given an explicit file type option.
*/
char
guess_file_type (buf, fname)
struct buffer *buf; char *fname;
{
char *ptr = buf->text;
if (ptr[0] == '%' && ptr[1] == '!')
return 'f'; /* print PostScript as plain file */
if (ptr[0] == '\367' && ptr[1] == 2) {
fprintf (stderr, "lpr: %s is a TeX .dvi file, assuming -d\n", fname);
return 'd'; /* TeX .dvi file */
}
if (ptr[0] == '\100' && ptr[1] == '\357') {
fprintf (stderr, "lpr: %s is a C/A/T troff output file, assuming -t\n",
fname);
return 't'; /* C/A/T troff file */
}
return 'f'; /* default file type is plain file */
}
int
check_for_bogus_file (buf, type, filename)
struct buffer *buf; char type; char *filename;
{
char *ptr = buf->text;
if (buf->ptr == buf->text) {
fprintf (stderr, "lpr: skipping zero-length file %s\n", filename);
return EOF;
}
if (ptr[0] == '\037' && ptr[1] == '\235') {
fprintf (stderr, "lpr: %s is a compressed file -- ignoring it\n",
filename);
return EOF;
}
if (type == 'd') {
if (ptr[0] == '\367' && ptr[1] == '\002') {
/* sometimes .dvi files have trailing NULs when they
shouldn't have. Remove these from the buffer and
check that the .dvi file ends with a \337 byte. */
if (buf->ptr[-1] == '\0') {
while (buf->ptr[-1] == '\0')
--(buf->ptr);
}
if (buf->ptr[-1] == '\337')
return 0;
}
fprintf (stderr, "lpr: %s is not a valid .dvi file", filename);
return EOF;
}
if (memcmp (ptr, "!<arch>\n", 8) == 0) {
fprintf (stderr, "lpr: %s is a UNIX library archive -- ignoring it",
filename);
return EOF;
}
return 0;
}
/*
* Send a command to the remote server and wait for a response. Return
* the first byte of the response, or EOF on error.
*/
int
send_command (fd, buf, size)
int fd; char *buf; unsigned int size;
{
char x[1];
if (x_write (fd, buf, size) != size)
return EOF;
if (x_read (fd, x, 1) != 1)
return EOF;
return *x;
}
/*
* structure used to keep track of print jobs
*/
struct job {
int jobid; /* integer job id 1-999 */
int fd; /* fd of lpd socket */
int control_file_number; /* current file number */
int data_file_number; /* data_file_number */
struct buffer *cfile; /* buffer to build control file */
};
/*
* add a record to a control file
*/
void
control (job, cmd, arg)
struct job *job; char cmd; char *arg;
{
char buf[512];
sprintf (buf, "%c%s\n", cmd, arg);
job->cfile = append_string_to_buffer (job->cfile, buf, strlen (buf));
}
/*
* create a print job. Return a job ptr on success or NULL on error.
*/
struct job *
open_job (queuename)
char *queuename;
{
struct job *job;
char buf[512];
char x;
if ((job = (struct job *) calloc (1, sizeof (struct job))) == NULL)
return NULL;
/*
* generate a job #. Really, this should be maintained on a
* per-(host,queue) basis, so we won't have naming conflicts.
* for now, we just generate something pseudo-random.
*/
job->jobid = time (0) % 1000;
job->fd = open_lpd (lpd_server);
if (job->fd < 0) {
free (job);
return NULL;
}
sprintf (buf, "\2%s\n", queuename);
if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
if (isprint (x)) {
int foo;
*buf = x;
foo = x_read (job->fd, buf+1, sizeof(buf)-1);
fprintf (stderr,
"lpr: server %s refused job with message:\n",
lpd_server);
fprintf (stderr, "%.*s", foo+1, buf);
}
else {
fprintf (stderr,
"lpr: server %s refused job for printer %s\n",
lpd_server, queuename);
}
close (job->fd);
free (job);
return NULL;
}
job->control_file_number = 0;
job->data_file_number = 0;
job->cfile = create_buffer (1000);
control (job, 'H', hostname);
control (job, 'P', username);
if (hflag == 0) {
control (job, 'J', jobtitle);
control (job, 'C', jobclass);
}
control (job, 'L', username);
if (title)
control (job, 'T', title);
if (mflag)
control (job, 'M', email_address);
return job;
}
void
concoct_file_name (c, job, str)
char c; struct job *job; char *str;
{
int x = c == 'd' ? job->data_file_number++ : job->control_file_number++;
sprintf (str, "%cf%c%03d%s", c,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[x],
job->jobid, hostname);
}
/*
* Send a file to be printed. Return 1 on success and 0 on error.
* (i.e. # of files sent).
* print diagnostic messages to stderr as necessary
* If file == NULL, print standard input
*/
int
send_print_file (job, file, file_type)
struct job *job; char *file; char file_type;
{
int estimated_size; /* how big we think the file is */
int max_size; /* max size to print */
int real_size;
int fd = EOF; /* fd of file */
struct buffer *dfile = NULL; /* buffer to read file into */
char *reason = NULL; /* reason file xfer failed */
char data_file_name[512]; /* name of temporary data file */
char buf[512];
int x;
int i;
/*
* open the file and find out how big it is
* estimated_size is used to determine how much space to allocate.
* max_size is used to decide how much to read in. Under VMS
* we don't ever want to read too much, because we might get
* unwanted garbage at the end of a fixed-length record file.
*/
if (file) {
struct stat sbuf;
if (stat (file, &sbuf) < 0) {
perror (file);
return 0;
}
max_size = estimated_size = sbuf.st_size;
if ((fd = open (file, 0)) < 0) {
perror (file);
return 0;
}
}
else {
struct stat sbuf;
file = "standard input"; /* for page headers, error messages */
estimated_size = 64000;
max_size = 5*1024*1024; /* 5 megabytes */
fd = 0;
#ifdef unix
/*
* UNIX-specific performance optimization:
* If standard input is an ordinary file, get size estimate
* with fstat()
*/
if (fstat (fd, &sbuf) < 0) {
if ((sbuf.st_mode & S_IFMT) == S_IFREG)
estimated_size = sbuf.st_size;
}
#endif
}
/*
* create a buffer and read the file into it.
*/
concoct_file_name ('d', job, data_file_name);
if ((dfile = create_buffer (estimated_size)) == NULL) {
reason = "file too big to fit in memory";
goto abort;
}
if ((dfile = read_file_into_buffer (dfile, fd, max_size)) == NULL) {
reason = "error reading file";
goto abort;
}
/*
* file transfer successful. Add this file to the print job,
* clean up, and return.
*/
if (file_type == '?')
file_type = guess_file_type (dfile, file);
/*
* check for bogus file formats. Refuse to print anything that
* is obviously bogus.
*/
if (check_for_bogus_file (dfile, file_type, file))
goto okay;
/*
* transfer the file to the server, with error checking
*/
sprintf (buf, "\3%d %s\n", buffer_size(dfile), data_file_name);
if ((x = send_command (job->fd, buf, strlen (buf))) != 0) {
switch (x) {
case 1:
break;
case 2:
reason = "not enough disk space on server (or file is too large)";
break;
case EOF:
reason = "connection to printer server broken";
break;
default:
if (isprint (x)) {
*buf = x;
x = x_read (job->fd, buf + 1, sizeof (buf) - 1);
buf[x+1] = '\0';
reason = buf;
}
}
goto abort;
}
if (send_file_from_buffer (job->fd, dfile) != 0)
goto abort;
if (send_command (job->fd, "", 1) < 0)
goto abort;
if (file_type == 'p' && !title)
control (job, 'P', file);
for (i = 0; i < num_copies; ++i)
control (job, file_type, data_file_name);
control (job, 'U', data_file_name);
control (job, 'N', file);
okay:
free_buffer (dfile);
close (fd);
return 1;
/*
* file transfer failed. print error message and clean up
*/
abort:
fprintf (stderr, "lpr: unable to send file %s to print server %s\n",
file, lpd_server);
if (reason)
fprintf (stderr, "reason: %s\n", reason);
if (dfile)
free_buffer (dfile);
if (fd > 0)
close (fd);
return 0;
}
/*
* send the control file. Return 0 on success, nonzero on error.
*/
send_control_file (job)
struct job *job;
{
char buf[512];
char control_file_name[512];
concoct_file_name ('c', job, control_file_name);
sprintf (buf, "\2%d %s\n", job->cfile->ptr - job->cfile->text,
control_file_name);
if (send_command (job->fd, buf, strlen (buf)) < 0)
return 1;
if (send_file_from_buffer (job->fd, job->cfile) != 0)
return 1;
if (send_command (job->fd, "", 1) < 0)
return 1;
return 0;
}
/*
* close a job normally and delete its resources
*/
int
close_job (job)
struct job *job;
{
int x;
if (job == NULL)
return EOF;
x = send_control_file (job);
if (job->cfile)
free_buffer (job->cfile);
close (job->fd);
cfree (job);
return x;
}
/*
* abort a job and delete its resources
*/
void
abort_job (job)
struct job *job;
{
if (job == NULL)
return;
x_write (job->fd, "\1\n", 2);
close (job->fd);
if (job->cfile)
free_buffer (job->cfile);
cfree (job);
}
char *
get_lpd_server ()
{
FILE *fp;
static char *buf[512];
if ((fp = fopen ("/etc/LPD_SERVER", "r")) == (FILE *) NULL)
return NULL;
if (fscanf (fp, " %511s", buf) != 1)
return NULL;
return (char *) buf;
}
/*
* Dummy main program exists to find out what name we are being called
* by (under UNIX, anyway) and act appropriately. This program has
* multiple personalities...
*/
main (argc, argv)
int argc; char **argv;
{
#ifdef unix
char *progname = NULL;
char *strrchr ();
#endif
char *p;
/*
* inherit some defaults from the environment
*/
printer = getenv ("PRINTER");
if (printer == NULL)
printer = "lp";
lpd_server = getenv ("LPD_SERVER");
if (lpd_server == NULL)
lpd_server = get_lpd_server ();
sysdep ();
#ifdef unix
/*
* look at the last component of the name we were invoked with
* and determine how to behave.
*/
progname = strrchr (argv[0], '/');
if (progname == NULL)
progname = argv[0];
else
progname++;
if (strcmp (progname, "lpq") == 0)
return (lpq (argc, argv));
else if (strcmp (progname, "lprm") == 0)
return (lprm (argc, argv));
#endif
/*
* if first argument is -remove or -delete, behave as lprm
* if first argumetn is -showqueue, behave as lpq
*/
if (argc > 1) {
if (strcmp (argv[1], "-remove") == 0)
return (lprm (argc-1, argv+1));
else if (strcmp (argv[1], "-delete") == 0)
return (lprm (argc-1, argv+1));
else if (strcmp (argv[1], "-showqueue") == 0)
return (lpq (argc-1, argv+1));
}
return (lpr (argc, argv));
}
/*
* queue one or more files for printing
*/
lpr (argc, argv)
int argc; char **argv;
{
struct job *job = NULL;
int i;
int file_args = 0;
int files_printed = 0;
jobclass = hostname;
jobtitle = NULL;
for (i = 1; i < argc; ++i) {
if (*argv[i] == '-')
i += option (argv[i], argv[i+1]);
else {
if (!jobtitle) {
char *ptr = strrchr (argv[i], '/');
jobtitle = ptr ? ptr + 1 : argv[i];
}
if (job == NULL && (job = open_job (printer)) == NULL)
exit (EXIT_FAIL);
file_args++;
if (send_print_file (job, argv[i], file_type)) {
files_printed++;
if (rflag)
mark_for_delete (argv[i]);
}
}
}
if (file_args == 0) {
if (!jobtitle)
jobtitle = "stdin";
if ((job = open_job (printer)) == NULL)
exit (EXIT_FAIL);
files_printed += send_print_file (job, 0, file_type);
}
if (files_printed > 0) {
if (close_job (job)) {
delete_marked_files ();
exit (EXIT_OK);
}
else
exit (EXIT_FAIL);
}
else
exit (EXIT_FAIL);
exit (EXIT_OK);
}
/*
* print contents of printer queue
* "lpq -l" prints in long format
*/
lpq (argc, argv)
int argc; char **argv;
{
int i;
char buf[512];
int fd;
int x;
for (i = 1; i < argc ; ++i) {
if (*argv[i] == '-')
i += option (argv[i], argv[i+1]);
else
break;
}
if ((fd = open_lpd (lpd_server)) < 0)
exit (EXIT_FAIL);
if (lflag)
sprintf (buf, "\004%s", printer);
else
sprintf (buf, "\003%s", printer);
for (; i < argc; ++i) {
strcat (buf, " ");
strcat (buf, argv[i]);
}
strcat (buf, "\n");
if (x_write (fd, buf, strlen (buf)) != 0) {
while ((x = x_read (fd, buf, sizeof buf)) > 0)
fwrite (buf, sizeof (char), x, stdout);
}
close (fd);
return 0;
}
/*
* remove jobs from queue
*/
lprm (argc, argv)
int argc; char **argv;
{
int fd;
int i;
char buf[512];
int x;
int response_length = 0;
int remove_all = 0;
for (i = 1; i < argc; ++i) {
if (strcmp (argv[i], "-") == 0)
remove_all++;
else if (*argv[i] == '-')
i += option (argv[i], argv[i+1]);
else
break;
}
if ((fd = open_lpd (lpd_server)) < 0)
exit (EXIT_FAIL);
/*
* If user asks to remove all queued files with "lprm -",
* need to check to see if user is privileged to do so.
* Allow root to remove all queued files, but any other
* user will just remove his/her own queued files.
* (remote server will only delete files queued by this system)
*
* "-all" is a magic user name which means delete all
* entries from this system.
*/
if (remove_all) {
#ifdef unix
if (strcmp (username, "root") == 0)
sprintf (buf, "\005%s %s", printer, "-all");
else
sprintf (buf, "\005%s %s %s", printer, username, username);
#else
sprintf (buf, "\005%s %s %s", printer, username, username);
#endif
}
else {
sprintf (buf, "\005%s %s", printer, username);
}
for (; i < argc; ++i) {
strcat (buf, " ");
strcat (buf, argv[i]);
}
strcat (buf, "\n");
if (x_write (fd, buf, strlen (buf)) != 0) {
while ((x = x_read (fd, buf, sizeof buf)) > 0) {
fwrite (buf, sizeof (char), x, stdout);
response_length += x;
}
}
close (fd);
/* If response_length is zero, assume the remove command failed.
Otherwise we should have received some confirmation message */
if (response_length == 0)
return 1;
return 0;
}