From 98f6cc540138b922ca6c1601fd61b54ad3e3a8a0 Mon Sep 17 00:00:00 2001 From: Garance A Drosehn <gad@FreeBSD.org> Date: Tue, 23 Apr 2002 00:06:10 +0000 Subject: [PATCH] Implement new printcap option of "rc" aka "remote.resend_copies". This is a boolean option, and if it is specified in a print queue for a remote host, it causes lpd to resend the data file for each copy the user requested on 'lpr -#n'. This is useful for network printers which accept lpd-style jobs, but which ignore the control file (and thus they ignore any request for multiple copies). PR: 25635 Reviewed by: short review on freebsd-audit MFC after: 6 days --- usr.sbin/lpr/common_source/lp.h | 1 + usr.sbin/lpr/common_source/printcap.c | 1 + usr.sbin/lpr/lpd/printjob.c | 59 ++++++++++++++++++++++----- usr.sbin/lpr/lpr/printcap.5 | 20 +++++++++ 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h index a2e0bff7cc4b..6faaf4d89929 100644 --- a/usr.sbin/lpr/common_source/lp.h +++ b/usr.sbin/lpr/common_source/lp.h @@ -72,6 +72,7 @@ struct printer { long page_width; /* PW: page width */ long page_pwidth; /* PX: page width in pixels */ long page_plength; /* PY: page length in pixels */ + long resend_copies; /* RC: resend copies to remote host */ char *restrict_grp; /* RG: restricted group */ char *remote_host; /* RM: remote machine name */ char *remote_queue; /* RP: remote printer name */ diff --git a/usr.sbin/lpr/common_source/printcap.c b/usr.sbin/lpr/common_source/printcap.c index d70c5b100376..d9498936e727 100644 --- a/usr.sbin/lpr/common_source/printcap.c +++ b/usr.sbin/lpr/common_source/printcap.c @@ -257,6 +257,7 @@ getprintcap_int(char *bp, struct printer *pp) &pp->status_file)); CHK(capdb_getaltstr(bp, "tr", "job.trailer", 0, &pp->trailer)); + pp->resend_copies = capdb_getaltlog(bp, "rc", "remote.resend_copies"); pp->restricted = capdb_getaltlog(bp, "rs", "daemon.restricted"); pp->short_banner = capdb_getaltlog(bp, "sb", "banner.short"); pp->no_copies = capdb_getaltlog(bp, "sc", "job.no_copies"); diff --git a/usr.sbin/lpr/lpd/printjob.c b/usr.sbin/lpr/lpd/printjob.c index 3ac859e31a78..59ccccb1124b 100644 --- a/usr.sbin/lpr/lpd/printjob.c +++ b/usr.sbin/lpr/lpd/printjob.c @@ -146,7 +146,7 @@ static void scan_out(struct printer *_pp, int _scfd, char *_scsp, int _dlm); static char *scnline(int _key, char *_p, int _c); static int sendfile(struct printer *_pp, int _type, char *_file, - char _format); + char _format, int _copyreq); static int sendit(struct printer *_pp, char *_file); static void sendmail(struct printer *_pp, char *_userid, int _bombed); static void setty(const struct printer *_pp); @@ -868,7 +868,7 @@ print(struct printer *pp, int format, char *file) static int sendit(struct printer *pp, char *file) { - register int i, err = OK; + int dfcopies, err, i; char *cp, last[BUFSIZ]; /* @@ -895,6 +895,7 @@ sendit(struct printer *pp, char *file) /* * pass 1 */ + err = OK; while (getline(cfp)) { again: if (line[0] == 'S') { @@ -925,11 +926,14 @@ sendit(struct printer *pp, char *file) } else if (line[0] == 'I') { strlcpy(indent+2, line + 1, sizeof(indent) - 2); } else if (line[0] >= 'a' && line[0] <= 'z') { + dfcopies = 1; strcpy(last, line); - while ((i = getline(cfp)) != 0) - if (strcmp(last, line)) + while ((i = getline(cfp)) != 0) { + if (strcmp(last, line) != 0) break; - switch (sendfile(pp, '\3', last+1, *last)) { + dfcopies++; + } + switch (sendfile(pp, '\3', last+1, *last, dfcopies)) { case OK: if (i) goto again; @@ -945,7 +949,7 @@ sendit(struct printer *pp, char *file) break; } } - if (err == OK && sendfile(pp, '\2', file, '\0') > 0) { + if (err == OK && sendfile(pp, '\2', file, '\0', 1) > 0) { (void) fclose(cfp); return(REPRINT); } @@ -969,13 +973,13 @@ sendit(struct printer *pp, char *file) * Return positive if we should try resending. */ static int -sendfile(struct printer *pp, int type, char *file, char format) +sendfile(struct printer *pp, int type, char *file, char format, int copyreq) { int i, amt; struct stat stb; char *av[15], *filtcmd; char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4]; - int filtstat, narg, resp, sfd, sfres, sizerr, statrc; + int copycnt, filtstat, narg, resp, sfd, sfres, sizerr, statrc; statrc = lstat(file, &stb); if (statrc < 0) { @@ -1102,7 +1106,15 @@ sendfile(struct printer *pp, int type, char *file, char format) lseek(sfd, 0, SEEK_SET); } - (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); + copycnt = 0; +sendagain: + copycnt++; + + if (copycnt < 2) + (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); + else + (void) sprintf(buf, "%c%qd %s_c%d\n", type, stb.st_size, + file, copycnt); amt = strlen(buf); for (i = 0; ; i++) { if (write(pfd, buf, amt) != amt || @@ -1121,6 +1133,10 @@ sendfile(struct printer *pp, int type, char *file, char format) } if (i) pstatus(pp, "sending to %s", pp->remote_host); + /* + * XXX - we should change trstat_init()/trstat_write() to include + * the copycnt in the statistics record it may write. + */ if (type == '\3') trstat_init(pp, file, job_dfcnt); for (i = 0; i < stb.st_size; i += BUFSIZ) { @@ -1146,9 +1162,30 @@ sendfile(struct printer *pp, int type, char *file, char format) sfres = REPRINT; goto return_sfres; } - if (type == '\3') + if (type == '\3') { trstat_write(pp, TR_SENDING, stb.st_size, logname, - pp->remote_host, origin_host); + pp->remote_host, origin_host); + /* + * Usually we only need to send one copy of a datafile, + * because the control-file will simply print the same + * file multiple times. However, some printers ignore + * the control file, and simply print each data file as + * it arrives. For such "remote hosts", we need to + * transfer the same data file multiple times. Such a + * a host is indicated by adding 'rc' to the printcap + * entry. + * XXX - Right now this ONLY works for remote hosts which + * do ignore the name of the data file, because + * this sends the file multiple times with slight + * changes to the filename. To do this right would + * require that we also rewrite the control file + * to match those filenames. + */ + if (pp->resend_copies && (copycnt < copyreq)) { + lseek(sfd, 0, SEEK_SET); + goto sendagain; + } + } sfres = OK; return_sfres: diff --git a/usr.sbin/lpr/lpr/printcap.5 b/usr.sbin/lpr/lpr/printcap.5 index 0f42f6779132..eef7f3bd39b8 100644 --- a/usr.sbin/lpr/lpr/printcap.5 +++ b/usr.sbin/lpr/lpr/printcap.5 @@ -109,6 +109,7 @@ blocks), zero = unlimited .It "pw num 132 page width (in characters)" .It "px num 0 page width in pixels (horizontal)" .It "py num 0 page length in pixels (vertical)" +.It "rc bool false when sending to a remote host, resend copies (see below)" .It "rf str" Ta Dv NULL Ta No "filter for printing" .Tn FORTRAN style text files @@ -157,6 +158,7 @@ Each two-letter capability has a human-readable alternate name. .It "pw page.width" .It "px page.pwidth" .It "py page.plength" +.It "rc remote.resend_copies" .It "rf filt.fortran" .It "rg daemon.restrictgrp" .It "rm remote.host" @@ -325,6 +327,24 @@ will therefore happen before .Xr pr 1 is executed rather than afterwards. .Pp +There are some models of network printers which accept jobs from +.Xr lpd 8 , but they ignore the control file for a job and simply print +each data file as it arrives at the printer. +One side-effect of this behavior is that the printer will ignore any request +for multiple copies as given with the +.Fl # +flag on the +.Xr lpr 1 command. +The +.Cm rc +entry will cause +.Xr lpd 8 to resend each data file for each copy that the user +originally requested. +Note that the +.Cm rc +entry should only be specified on hosts which send jobs directly to +the printer. +.Pp If .Cm lp is specified as