11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 4. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
30117541Sgad#if 0
31117592Sgad#ifndef lint
3215648Sjoergstatic char sccsid[] = "@(#)displayq.c	8.4 (Berkeley) 4/28/95";
33117592Sgad#endif /* not lint */
34117541Sgad#endif
35117592Sgad
36117541Sgad#include "lp.cdefs.h"		/* A cross-platform version of <sys/cdefs.h> */
37117541Sgad__FBSDID("$FreeBSD$");
381553Srgrimes
391553Srgrimes#include <sys/param.h>
401553Srgrimes#include <sys/stat.h>
411553Srgrimes
4231492Swollman#include <ctype.h>
4331492Swollman#include <dirent.h>
44241852Seadler#include <err.h>
4531492Swollman#include <errno.h>
4631492Swollman#include <fcntl.h>
471553Srgrimes#include <signal.h>
481553Srgrimes#include <stdio.h>
491553Srgrimes#include <stdlib.h>
501553Srgrimes#include <string.h>
5131492Swollman#define psignal foil_gcc_psignal
5231492Swollman#define	sys_siglist foil_gcc_siglist
5331492Swollman#include <unistd.h>
5431492Swollman#undef psignal
5531492Swollman#undef sys_siglist
5631492Swollman
571553Srgrimes#include "lp.h"
581553Srgrimes#include "lp.local.h"
591553Srgrimes#include "pathnames.h"
601553Srgrimes
611553Srgrimes/*
621553Srgrimes * Routines to display the state of the queue.
631553Srgrimes */
641553Srgrimes#define JOBCOL	40		/* column for job # in -l format */
651553Srgrimes#define OWNCOL	7		/* start of Owner column in normal */
661553Srgrimes#define SIZCOL	62		/* start of Size column in normal */
671553Srgrimes
681553Srgrimes/*
69194859Sgad * isprint() takes a parameter of 'int', but expect values in the range
70194859Sgad * of unsigned char.  Define a wrapper which takes a value of type 'char',
71194859Sgad * whether signed or unsigned, and ensure it ends up in the right range.
72194859Sgad */
73194859Sgad#define	isprintch(Anychar) isprint((u_char)(Anychar))
74194859Sgad
75194859Sgad/*
761553Srgrimes * Stuff for handling job specifications
771553Srgrimes */
781553Srgrimesstatic int	col;		/* column on screen */
7982557Skrisstatic char	current[MAXNAMLEN+1];	/* current file being printed */
8082557Skrisstatic char	file[MAXNAMLEN+1];	/* print file name */
811553Srgrimesstatic int	first;		/* first file in ``files'' column? */
821553Srgrimesstatic int	garbage;	/* # of garbage cf files */
831553Srgrimesstatic int	lflag;		/* long output option */
841553Srgrimesstatic int	rank;		/* order to be printed (-1=none, 0=active) */
851553Srgrimesstatic long	totsize;	/* total print job size in bytes */
861553Srgrimes
8778146Sgadstatic const char  *head0 = "Rank   Owner      Job  Files";
8878146Sgadstatic const char  *head1 = "Total Size\n";
891553Srgrimes
9078146Sgadstatic void	alarmhandler(int _signo);
91194859Sgadstatic void	filtered_write(char *_obuffer, int _wlen, FILE *_wstream);
92241852Seadlerstatic void	daemonwarn(const struct printer *_pp);
9326844Sjoerg
941553Srgrimes/*
951553Srgrimes * Display the current state of the queue. Format = 1 if long format.
961553Srgrimes */
971553Srgrimesvoid
9878146Sgaddisplayq(struct printer *pp, int format)
991553Srgrimes{
10068401Sgad	register struct jobqueue *q;
10127618Simp	register int i, nitems, fd, ret;
10282557Skris	char *cp, *endp;
10368401Sgad	struct jobqueue **queue;
1041553Srgrimes	struct stat statb;
1051553Srgrimes	FILE *fp;
10626844Sjoerg	void (*savealrm)(int);
1071553Srgrimes
1081553Srgrimes	lflag = format;
1091553Srgrimes	totsize = 0;
1101553Srgrimes	rank = -1;
11131492Swollman
11231492Swollman	if ((cp = checkremote(pp))) {
1131553Srgrimes		printf("Warning: %s\n", cp);
11431492Swollman		free(cp);
11531492Swollman	}
1161553Srgrimes
1171553Srgrimes	/*
1181553Srgrimes	 * Print out local queue
1191553Srgrimes	 * Find all the control files in the spooling directory
1201553Srgrimes	 */
121241852Seadler	PRIV_START
12231492Swollman	if (chdir(pp->spool_dir) < 0)
12331492Swollman		fatal(pp, "cannot chdir to spooling directory: %s",
12431492Swollman		      strerror(errno));
125241852Seadler	PRIV_END
12631492Swollman	if ((nitems = getq(pp, &queue)) < 0)
12731492Swollman		fatal(pp, "cannot examine spooling area\n");
128241852Seadler	PRIV_START
12931492Swollman	ret = stat(pp->lock_file, &statb);
130241852Seadler	PRIV_END
13127618Simp	if (ret >= 0) {
13231492Swollman		if (statb.st_mode & LFM_PRINT_DIS) {
13331492Swollman			if (pp->remote)
13478300Sgad				printf("%s: ", local_host);
13531492Swollman			printf("Warning: %s is down: ", pp->printer);
136241852Seadler			PRIV_START
13731492Swollman			fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
138241852Seadler			PRIV_END
1391553Srgrimes			if (fd >= 0) {
1401553Srgrimes				while ((i = read(fd, line, sizeof(line))) > 0)
1411553Srgrimes					(void) fwrite(line, 1, i, stdout);
1421553Srgrimes				(void) close(fd);	/* unlocks as well */
1431553Srgrimes			} else
1441553Srgrimes				putchar('\n');
1451553Srgrimes		}
14631492Swollman		if (statb.st_mode & LFM_QUEUE_DIS) {
14731492Swollman			if (pp->remote)
14878300Sgad				printf("%s: ", local_host);
14931492Swollman			printf("Warning: %s queue is turned off\n",
15031492Swollman			       pp->printer);
1511553Srgrimes		}
1521553Srgrimes	}
1531553Srgrimes
1541553Srgrimes	if (nitems) {
155241852Seadler		PRIV_START
15631492Swollman		fp = fopen(pp->lock_file, "r");
157241852Seadler		PRIV_END
1581553Srgrimes		if (fp == NULL)
159241852Seadler			daemonwarn(pp);
1601553Srgrimes		else {
1611553Srgrimes			/* get daemon pid */
1621553Srgrimes			cp = current;
16382557Skris			endp = cp + sizeof(current) - 1;
16482557Skris			while ((i = getc(fp)) != EOF && i != '\n') {
16582557Skris				if (cp < endp)
16682557Skris					*cp++ = i;
16782557Skris			}
1681553Srgrimes			*cp = '\0';
1691553Srgrimes			i = atoi(current);
17027618Simp			if (i <= 0) {
17127618Simp				ret = -1;
17227618Simp			} else {
173241852Seadler				PRIV_START
17427618Simp				ret = kill(i, 0);
175241852Seadler				PRIV_END
17627618Simp			}
17727618Simp			if (ret < 0) {
178241852Seadler				daemonwarn(pp);
17927618Simp			} else {
1801553Srgrimes				/* read current file name */
1811553Srgrimes				cp = current;
18282557Skris				endp = cp + sizeof(current) - 1;
18382557Skris				while ((i = getc(fp)) != EOF && i != '\n') {
18482557Skris					if (cp < endp)
18582557Skris						*cp++ = i;
18682557Skris				}
1871553Srgrimes				*cp = '\0';
1881553Srgrimes				/*
1891553Srgrimes				 * Print the status file.
1901553Srgrimes				 */
19131492Swollman				if (pp->remote)
19278300Sgad					printf("%s: ", local_host);
193241852Seadler				PRIV_START
19431492Swollman				fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
195241852Seadler				PRIV_END
1961553Srgrimes				if (fd >= 0) {
19731492Swollman					while ((i = read(fd, line,
19831492Swollman							 sizeof(line))) > 0)
19931492Swollman						fwrite(line, 1, i, stdout);
20031492Swollman					close(fd);	/* unlocks as well */
2011553Srgrimes				} else
2021553Srgrimes					putchar('\n');
2031553Srgrimes			}
2041553Srgrimes			(void) fclose(fp);
2051553Srgrimes		}
2061553Srgrimes		/*
2071553Srgrimes		 * Now, examine the control files and print out the jobs to
2081553Srgrimes		 * be done for each user.
2091553Srgrimes		 */
2101553Srgrimes		if (!lflag)
2111553Srgrimes			header();
2121553Srgrimes		for (i = 0; i < nitems; i++) {
2131553Srgrimes			q = queue[i];
21468401Sgad			inform(pp, q->job_cfname);
2151553Srgrimes			free(q);
2161553Srgrimes		}
2171553Srgrimes		free(queue);
2181553Srgrimes	}
21931492Swollman	if (!pp->remote) {
2201553Srgrimes		if (nitems == 0)
2211553Srgrimes			puts("no entries");
2221553Srgrimes		return;
2231553Srgrimes	}
2241553Srgrimes
2251553Srgrimes	/*
2261553Srgrimes	 * Print foreign queue
2271553Srgrimes	 * Note that a file in transit may show up in either queue.
2281553Srgrimes	 */
2291553Srgrimes	if (nitems)
2301553Srgrimes		putchar('\n');
23131492Swollman	(void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
23231492Swollman			pp->remote_queue);
2331553Srgrimes	cp = line;
23427757Simp	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
2351553Srgrimes		cp += strlen(cp);
2361553Srgrimes		(void) sprintf(cp, " %d", requ[i]);
2371553Srgrimes	}
23822466Simp	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
23927757Simp		sizeof(line) - 1; i++) {
2401553Srgrimes		cp += strlen(cp);
2411553Srgrimes		*cp++ = ' ';
2421553Srgrimes		(void) strcpy(cp, user[i]);
2431553Srgrimes	}
2441553Srgrimes	strcat(line, "\n");
24526844Sjoerg	savealrm = signal(SIGALRM, alarmhandler);
24631492Swollman	alarm(pp->conn_timeout);
24731492Swollman	fd = getport(pp, pp->remote_host, 0);
24831020Sjoerg	alarm(0);
24926844Sjoerg	(void)signal(SIGALRM, savealrm);
2501553Srgrimes	if (fd < 0) {
25178300Sgad		if (from_host != local_host)
25278300Sgad			printf("%s: ", local_host);
25331492Swollman		printf("connection to %s is down\n", pp->remote_host);
2541553Srgrimes	}
2551553Srgrimes	else {
2561553Srgrimes		i = strlen(line);
2571553Srgrimes		if (write(fd, line, i) != i)
25831492Swollman			fatal(pp, "Lost connection");
2591553Srgrimes		while ((i = read(fd, line, sizeof(line))) > 0)
260194859Sgad			filtered_write(line, i, stdout);
261194859Sgad		filtered_write(NULL, -1, stdout);
2621553Srgrimes		(void) close(fd);
2631553Srgrimes	}
2641553Srgrimes}
2651553Srgrimes
2661553Srgrimes/*
267194859Sgad * The lpq-info read from remote hosts may contain unprintable characters,
268194859Sgad * or carriage-returns instead of line-feeds.  Clean those up before echoing
269194859Sgad * the lpq-info line(s) to stdout.  The info may also be missing any kind of
270194859Sgad * end-of-line character.  This also turns CRLF and LFCR into a plain LF.
271194859Sgad *
272194859Sgad * This routine may be called multiple times to process a single set of
273194859Sgad * information, and after a set is finished this routine must be called
274194859Sgad * one extra time with NULL specified as the buffer address.
275194859Sgad */
276194859Sgadstatic void
277194859Sgadfiltered_write(char *wbuffer, int wlen, FILE *wstream)
278194859Sgad{
279194859Sgad	static char lastchar, savedchar;
280194859Sgad	char *chkptr, *dest_end, *dest_ch, *nxtptr, *w_end;
281194859Sgad	int destlen;
282194859Sgad	char destbuf[BUFSIZ];
283194859Sgad
284194859Sgad	if (wbuffer == NULL) {
285194859Sgad		if (savedchar != '\0') {
286194859Sgad			if (savedchar == '\r')
287194859Sgad				savedchar = '\n';
288194859Sgad			fputc(savedchar, wstream);
289194859Sgad			lastchar = savedchar;
290194859Sgad			savedchar = '\0';
291194859Sgad		}
292194859Sgad		if (lastchar != '\0' && lastchar != '\n')
293194859Sgad			fputc('\n', wstream);
294194859Sgad		lastchar = '\0';
295194859Sgad		return;
296194859Sgad	}
297194859Sgad
298194859Sgad	dest_ch = &destbuf[0];
299194859Sgad	dest_end = dest_ch + sizeof(destbuf);
300194859Sgad	chkptr = wbuffer;
301194859Sgad	w_end = wbuffer + wlen;
302194859Sgad	lastchar = '\0';
303194859Sgad	if (savedchar != '\0') {
304194859Sgad		chkptr = &savedchar;
305194859Sgad		nxtptr = wbuffer;
306194859Sgad	} else
307194859Sgad		nxtptr = chkptr + 1;
308194859Sgad
309194859Sgad	while (chkptr < w_end) {
310194859Sgad		if (nxtptr < w_end) {
311194859Sgad			if ((*chkptr == '\r' && *nxtptr == '\n') ||
312194859Sgad			    (*chkptr == '\n' && *nxtptr == '\r')) {
313194859Sgad				*dest_ch++ = '\n';
314194859Sgad				/* want to skip past that second character */
315194859Sgad				nxtptr++;
316194859Sgad				goto check_next;
317194859Sgad			}
318194859Sgad		} else {
319194859Sgad			/* This is the last byte in the buffer given on this
320194859Sgad			 * call, so check if it could be the first-byte of a
321194859Sgad			 * significant two-byte sequence.  If it is, then
322194859Sgad			 * don't write it out now, but save for checking in
323194859Sgad			 * the next call.
324194859Sgad			 */
325194859Sgad			savedchar = '\0';
326194859Sgad			if (*chkptr == '\r' || *chkptr == '\n') {
327194859Sgad				savedchar = *chkptr;
328194859Sgad				break;
329194859Sgad			}
330194859Sgad		}
331194859Sgad		if (*chkptr == '\r')
332194859Sgad			*dest_ch++ = '\n';
333194859Sgad#if 0		/* XXX - don't translate unprintable characters (yet) */
334194859Sgad		else if (*chkptr != '\t' && *chkptr != '\n' &&
335194859Sgad		    !isprintch(*chkptr))
336194859Sgad			*dest_ch++ = '?';
337194859Sgad#endif
338194859Sgad		else
339194859Sgad			*dest_ch++ = *chkptr;
340194859Sgad
341194859Sgadcheck_next:
342194859Sgad		chkptr = nxtptr;
343194859Sgad		nxtptr = chkptr + 1;
344194859Sgad		if (dest_ch >= dest_end) {
345194859Sgad			destlen = dest_ch - &destbuf[0];
346194859Sgad			fwrite(destbuf, 1, destlen, wstream);
347194859Sgad			lastchar = destbuf[destlen - 1];
348194859Sgad			dest_ch = &destbuf[0];
349194859Sgad		}
350194859Sgad	}
351194859Sgad	destlen = dest_ch - &destbuf[0];
352194859Sgad	if (destlen > 0) {
353194859Sgad		fwrite(destbuf, 1, destlen, wstream);
354194859Sgad		lastchar = destbuf[destlen - 1];
355194859Sgad	}
356194859Sgad}
357194859Sgad
358194859Sgad/*
3591553Srgrimes * Print a warning message if there is no daemon present.
3601553Srgrimes */
36128621Sjoergstatic void
362241852Seadlerdaemonwarn(const struct printer *pp)
3631553Srgrimes{
36431492Swollman	if (pp->remote)
36578300Sgad		printf("%s: ", local_host);
3661553Srgrimes	puts("Warning: no daemon present");
3671553Srgrimes	current[0] = '\0';
3681553Srgrimes}
3691553Srgrimes
3701553Srgrimes/*
3711553Srgrimes * Print the header for the short listing format
3721553Srgrimes */
3731553Srgrimesvoid
37478146Sgadheader(void)
3751553Srgrimes{
37679739Sgad	printf("%s", head0);
3771553Srgrimes	col = strlen(head0)+1;
3781553Srgrimes	blankfill(SIZCOL);
37979739Sgad	printf("%s", head1);
3801553Srgrimes}
3811553Srgrimes
3821553Srgrimesvoid
38378146Sgadinform(const struct printer *pp, char *cf)
3841553Srgrimes{
385139464Sgad	int copycnt, jnum;
38668100Sgad	char	 savedname[MAXPATHLEN+1];
38768100Sgad	FILE	*cfp;
3881553Srgrimes
3891553Srgrimes	/*
3901553Srgrimes	 * There's a chance the control file has gone away
3911553Srgrimes	 * in the meantime; if this is the case just keep going
3921553Srgrimes	 */
393241852Seadler	PRIV_START
3941553Srgrimes	if ((cfp = fopen(cf, "r")) == NULL)
3951553Srgrimes		return;
396241852Seadler	PRIV_END
3971553Srgrimes
3981553Srgrimes	if (rank < 0)
3991553Srgrimes		rank = 0;
40031492Swollman	if (pp->remote || garbage || strcmp(cf, current))
4011553Srgrimes		rank++;
40268100Sgad
40368100Sgad	/*
40468100Sgad	 * The cf-file may include commands to print more than one datafile
40568100Sgad	 * from the user.  For each datafile, the cf-file contains at least
40668100Sgad	 * one line which starts with some format-specifier ('a'-'z'), and
40768100Sgad	 * a second line ('N'ame) which indicates the original name the user
40868100Sgad	 * specified for that file.  There can be multiple format-spec lines
40968100Sgad	 * for a single Name-line, if the user requested multiple copies of
41068100Sgad	 * that file.  Standard lpr puts the format-spec line(s) before the
41168100Sgad	 * Name-line, while lprNG puts the Name-line before the format-spec
41268100Sgad	 * line(s).  This section needs to handle the lines in either order.
41368100Sgad	 */
41468100Sgad	copycnt = 0;
41568100Sgad	file[0] = '\0';
41668100Sgad	savedname[0] = '\0';
417139464Sgad	jnum = calc_jobnum(cf, NULL);
4181553Srgrimes	while (getline(cfp)) {
4191553Srgrimes		switch (line[0]) {
4201553Srgrimes		case 'P': /* Was this file specified in the user's list? */
4211553Srgrimes			if (!inlist(line+1, cf)) {
4221553Srgrimes				fclose(cfp);
4231553Srgrimes				return;
4241553Srgrimes			}
4251553Srgrimes			if (lflag) {
4261553Srgrimes				printf("\n%s: ", line+1);
4271553Srgrimes				col = strlen(line+1) + 2;
4281553Srgrimes				prank(rank);
4291553Srgrimes				blankfill(JOBCOL);
4301553Srgrimes				printf(" [job %s]\n", cf+3);
4311553Srgrimes			} else {
4321553Srgrimes				col = 0;
4331553Srgrimes				prank(rank);
4341553Srgrimes				blankfill(OWNCOL);
435139464Sgad				printf("%-10s %-3d  ", line+1, jnum);
4361553Srgrimes				col += 16;
4371553Srgrimes				first = 1;
4381553Srgrimes			}
4391553Srgrimes			continue;
4401553Srgrimes		default: /* some format specifer and file name? */
4411553Srgrimes			if (line[0] < 'a' || line[0] > 'z')
44268100Sgad				break;
44368100Sgad			if (copycnt == 0 || strcmp(file, line+1) != 0) {
44480133Sgad				strlcpy(file, line + 1, sizeof(file));
44522466Simp			}
44668100Sgad			copycnt++;
44768100Sgad			/*
44868100Sgad			 * deliberately 'continue' to another getline(), so
44968100Sgad			 * all format-spec lines for this datafile are read
45068100Sgad			 * in and counted before calling show()
45168100Sgad			 */
4521553Srgrimes			continue;
4531553Srgrimes		case 'N':
45480133Sgad			strlcpy(savedname, line + 1, sizeof(savedname));
45568100Sgad			break;
45668100Sgad		}
45768100Sgad		if ((file[0] != '\0') && (savedname[0] != '\0')) {
45868100Sgad			show(savedname, file, copycnt);
45968100Sgad			copycnt = 0;
4601553Srgrimes			file[0] = '\0';
46168100Sgad			savedname[0] = '\0';
4621553Srgrimes		}
4631553Srgrimes	}
4641553Srgrimes	fclose(cfp);
46568100Sgad	/* check for a file which hasn't been shown yet */
46668100Sgad	if (file[0] != '\0') {
46768100Sgad		if (savedname[0] == '\0') {
46868100Sgad			/* a safeguard in case the N-ame line is missing */
46980133Sgad			strlcpy(savedname, file, sizeof(savedname));
47068100Sgad		}
47168100Sgad		show(savedname, file, copycnt);
47268100Sgad	}
4731553Srgrimes	if (!lflag) {
4741553Srgrimes		blankfill(SIZCOL);
4751553Srgrimes		printf("%ld bytes\n", totsize);
4761553Srgrimes		totsize = 0;
4771553Srgrimes	}
4781553Srgrimes}
4791553Srgrimes
4801553Srgrimesint
48178146Sgadinlist(char *uname, char *cfile)
4821553Srgrimes{
483139464Sgad	int *r, jnum;
484139464Sgad	char **u;
485139464Sgad	const char *cfhost;
4861553Srgrimes
4871553Srgrimes	if (users == 0 && requests == 0)
4881553Srgrimes		return(1);
4891553Srgrimes	/*
4901553Srgrimes	 * Check to see if it's in the user list
4911553Srgrimes	 */
4921553Srgrimes	for (u = user; u < &user[users]; u++)
49378146Sgad		if (!strcmp(*u, uname))
4941553Srgrimes			return(1);
4951553Srgrimes	/*
4961553Srgrimes	 * Check the request list
4971553Srgrimes	 */
498139464Sgad	jnum = calc_jobnum(cfile, &cfhost);
4991553Srgrimes	for (r = requ; r < &requ[requests]; r++)
500139464Sgad		if (*r == jnum && !strcmp(cfhost, from_host))
5011553Srgrimes			return(1);
5021553Srgrimes	return(0);
5031553Srgrimes}
5041553Srgrimes
5051553Srgrimesvoid
50678146Sgadshow(const char *nfile, const char *datafile, int copies)
5071553Srgrimes{
5081553Srgrimes	if (strcmp(nfile, " ") == 0)
5091553Srgrimes		nfile = "(standard input)";
5101553Srgrimes	if (lflag)
51178146Sgad		ldump(nfile, datafile, copies);
5121553Srgrimes	else
51378146Sgad		dump(nfile, datafile, copies);
5141553Srgrimes}
5151553Srgrimes
5161553Srgrimes/*
5171553Srgrimes * Fill the line with blanks to the specified column
5181553Srgrimes */
5191553Srgrimesvoid
52078146Sgadblankfill(int tocol)
5211553Srgrimes{
52278146Sgad	while (col++ < tocol)
5231553Srgrimes		putchar(' ');
5241553Srgrimes}
5251553Srgrimes
5261553Srgrimes/*
5271553Srgrimes * Give the abbreviated dump of the file names
5281553Srgrimes */
5291553Srgrimesvoid
53078146Sgaddump(const char *nfile, const char *datafile, int copies)
5311553Srgrimes{
5321553Srgrimes	struct stat lbuf;
53368101Sgad	const char etctmpl[] = ", ...";
53468101Sgad	char	 etc[sizeof(etctmpl)];
53568101Sgad	char	*lastsep;
53668101Sgad	short	 fill, nlen;
53768101Sgad	short	 rem, remetc;
5381553Srgrimes
5391553Srgrimes	/*
54068101Sgad	 * Print as many filenames as will fit
54168101Sgad	 *      (leaving room for the 'total size' field)
5421553Srgrimes	 */
54368101Sgad	fill = first ? 0 : 2;	/* fill space for ``, '' */
54468101Sgad	nlen = strlen(nfile);
54568101Sgad	rem = SIZCOL - 1 - col;
54668101Sgad	if (nlen + fill > rem) {
54768101Sgad		if (first) {
54868101Sgad			/* print the right-most part of the name */
54968101Sgad			printf("...%s ", &nfile[3+nlen-rem]);
55068101Sgad			col = SIZCOL;
55168101Sgad		} else if (rem > 0) {
55268101Sgad			/* fit as much of the etc-string as we can */
55368101Sgad			remetc = rem;
55468101Sgad			if (rem > strlen(etctmpl))
55568101Sgad				remetc = strlen(etctmpl);
55668101Sgad			etc[0] = '\0';
55768101Sgad			strncat(etc, etctmpl, remetc);
55879739Sgad			printf("%s", etc);
55968101Sgad			col += remetc;
56068101Sgad			rem -= remetc;
56168101Sgad			/* room for the last segment of this filename? */
56268101Sgad			lastsep = strrchr(nfile, '/');
56368101Sgad			if ((lastsep != NULL) && (rem > strlen(lastsep))) {
56468101Sgad				/* print the right-most part of this name */
56568101Sgad				printf("%s", lastsep);
56668101Sgad				col += strlen(lastsep);
56768101Sgad			} else {
56868101Sgad				/* do not pack any more names in here */
56968101Sgad				blankfill(SIZCOL);
57068101Sgad			}
5711553Srgrimes		}
5721553Srgrimes	} else {
57368101Sgad		if (!first)
5741553Srgrimes			printf(", ");
5751553Srgrimes		printf("%s", nfile);
57668101Sgad		col += nlen + fill;
5771553Srgrimes	}
57868101Sgad	first = 0;
57968101Sgad
580241852Seadler	PRIV_START
58178146Sgad	if (*datafile && !stat(datafile, &lbuf))
5821553Srgrimes		totsize += copies * lbuf.st_size;
583241852Seadler	PRIV_END
5841553Srgrimes}
5851553Srgrimes
5861553Srgrimes/*
5871553Srgrimes * Print the long info about the file
5881553Srgrimes */
5891553Srgrimesvoid
59078146Sgadldump(const char *nfile, const char *datafile, int copies)
5911553Srgrimes{
5921553Srgrimes	struct stat lbuf;
5931553Srgrimes
5941553Srgrimes	putchar('\t');
5951553Srgrimes	if (copies > 1)
5961553Srgrimes		printf("%-2d copies of %-19s", copies, nfile);
5971553Srgrimes	else
5981553Srgrimes		printf("%-32s", nfile);
59978146Sgad	if (*datafile && !stat(datafile, &lbuf))
60035998Sjb		printf(" %qd bytes", (long long) lbuf.st_size);
6011553Srgrimes	else
6021553Srgrimes		printf(" ??? bytes");
6031553Srgrimes	putchar('\n');
6041553Srgrimes}
6051553Srgrimes
6061553Srgrimes/*
6071553Srgrimes * Print the job's rank in the queue,
6081553Srgrimes *   update col for screen management
6091553Srgrimes */
6101553Srgrimesvoid
61178146Sgadprank(int n)
6121553Srgrimes{
6131553Srgrimes	char rline[100];
61478146Sgad	static const char *r[] = {
6151553Srgrimes		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
6161553Srgrimes	};
6171553Srgrimes
6181553Srgrimes	if (n == 0) {
6191553Srgrimes		printf("active");
6201553Srgrimes		col += 6;
6211553Srgrimes		return;
6221553Srgrimes	}
6231553Srgrimes	if ((n/10)%10 == 1)
6241553Srgrimes		(void)snprintf(rline, sizeof(rline), "%dth", n);
6251553Srgrimes	else
6261553Srgrimes		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
6271553Srgrimes	col += strlen(rline);
6281553Srgrimes	printf("%s", rline);
6291553Srgrimes}
63026844Sjoerg
63126844Sjoergvoid
63278146Sgadalarmhandler(int signo __unused)
63326844Sjoerg{
63478146Sgad	/* the signal is ignored */
63578146Sgad	/* (the '__unused' is just to avoid a compile-time warning) */
63626844Sjoerg}
637