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>
4431492Swollman#include <errno.h>
4531492Swollman#include <fcntl.h>
461553Srgrimes#include <signal.h>
471553Srgrimes#include <stdio.h>
481553Srgrimes#include <stdlib.h>
491553Srgrimes#include <string.h>
5031492Swollman#define psignal foil_gcc_psignal
5131492Swollman#define	sys_siglist foil_gcc_siglist
5231492Swollman#include <unistd.h>
5331492Swollman#undef psignal
5431492Swollman#undef sys_siglist
5531492Swollman
561553Srgrimes#include "lp.h"
571553Srgrimes#include "lp.local.h"
581553Srgrimes#include "pathnames.h"
591553Srgrimes
601553Srgrimes/*
611553Srgrimes * Routines to display the state of the queue.
621553Srgrimes */
631553Srgrimes#define JOBCOL	40		/* column for job # in -l format */
641553Srgrimes#define OWNCOL	7		/* start of Owner column in normal */
651553Srgrimes#define SIZCOL	62		/* start of Size column in normal */
661553Srgrimes
671553Srgrimes/*
68194859Sgad * isprint() takes a parameter of 'int', but expect values in the range
69194859Sgad * of unsigned char.  Define a wrapper which takes a value of type 'char',
70194859Sgad * whether signed or unsigned, and ensure it ends up in the right range.
71194859Sgad */
72194859Sgad#define	isprintch(Anychar) isprint((u_char)(Anychar))
73194859Sgad
74194859Sgad/*
751553Srgrimes * Stuff for handling job specifications
761553Srgrimes */
7727618Simpextern uid_t	uid, euid;
7827618Simp
791553Srgrimesstatic int	col;		/* column on screen */
8082557Skrisstatic char	current[MAXNAMLEN+1];	/* current file being printed */
8182557Skrisstatic char	file[MAXNAMLEN+1];	/* print file name */
821553Srgrimesstatic int	first;		/* first file in ``files'' column? */
831553Srgrimesstatic int	garbage;	/* # of garbage cf files */
841553Srgrimesstatic int	lflag;		/* long output option */
851553Srgrimesstatic int	rank;		/* order to be printed (-1=none, 0=active) */
861553Srgrimesstatic long	totsize;	/* total print job size in bytes */
871553Srgrimes
8878146Sgadstatic const char  *head0 = "Rank   Owner      Job  Files";
8978146Sgadstatic const char  *head1 = "Total Size\n";
901553Srgrimes
9178146Sgadstatic void	alarmhandler(int _signo);
92194859Sgadstatic void	filtered_write(char *_obuffer, int _wlen, FILE *_wstream);
9378146Sgadstatic void	warn(const struct printer *_pp);
9426844Sjoerg
951553Srgrimes/*
961553Srgrimes * Display the current state of the queue. Format = 1 if long format.
971553Srgrimes */
981553Srgrimesvoid
9978146Sgaddisplayq(struct printer *pp, int format)
1001553Srgrimes{
10168401Sgad	register struct jobqueue *q;
10227618Simp	register int i, nitems, fd, ret;
10382557Skris	char *cp, *endp;
10468401Sgad	struct jobqueue **queue;
1051553Srgrimes	struct stat statb;
1061553Srgrimes	FILE *fp;
10726844Sjoerg	void (*savealrm)(int);
1081553Srgrimes
1091553Srgrimes	lflag = format;
1101553Srgrimes	totsize = 0;
1111553Srgrimes	rank = -1;
11231492Swollman
11331492Swollman	if ((cp = checkremote(pp))) {
1141553Srgrimes		printf("Warning: %s\n", cp);
11531492Swollman		free(cp);
11631492Swollman	}
1171553Srgrimes
1181553Srgrimes	/*
1191553Srgrimes	 * Print out local queue
1201553Srgrimes	 * Find all the control files in the spooling directory
1211553Srgrimes	 */
12227618Simp	seteuid(euid);
12331492Swollman	if (chdir(pp->spool_dir) < 0)
12431492Swollman		fatal(pp, "cannot chdir to spooling directory: %s",
12531492Swollman		      strerror(errno));
12627618Simp	seteuid(uid);
12731492Swollman	if ((nitems = getq(pp, &queue)) < 0)
12831492Swollman		fatal(pp, "cannot examine spooling area\n");
12927618Simp	seteuid(euid);
13031492Swollman	ret = stat(pp->lock_file, &statb);
13127618Simp	seteuid(uid);
13227618Simp	if (ret >= 0) {
13331492Swollman		if (statb.st_mode & LFM_PRINT_DIS) {
13431492Swollman			if (pp->remote)
13578300Sgad				printf("%s: ", local_host);
13631492Swollman			printf("Warning: %s is down: ", pp->printer);
13727618Simp			seteuid(euid);
13831492Swollman			fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
13927618Simp			seteuid(uid);
1401553Srgrimes			if (fd >= 0) {
1411553Srgrimes				while ((i = read(fd, line, sizeof(line))) > 0)
1421553Srgrimes					(void) fwrite(line, 1, i, stdout);
1431553Srgrimes				(void) close(fd);	/* unlocks as well */
1441553Srgrimes			} else
1451553Srgrimes				putchar('\n');
1461553Srgrimes		}
14731492Swollman		if (statb.st_mode & LFM_QUEUE_DIS) {
14831492Swollman			if (pp->remote)
14978300Sgad				printf("%s: ", local_host);
15031492Swollman			printf("Warning: %s queue is turned off\n",
15131492Swollman			       pp->printer);
1521553Srgrimes		}
1531553Srgrimes	}
1541553Srgrimes
1551553Srgrimes	if (nitems) {
15627618Simp		seteuid(euid);
15731492Swollman		fp = fopen(pp->lock_file, "r");
15827618Simp		seteuid(uid);
1591553Srgrimes		if (fp == NULL)
16031492Swollman			warn(pp);
1611553Srgrimes		else {
1621553Srgrimes			/* get daemon pid */
1631553Srgrimes			cp = current;
16482557Skris			endp = cp + sizeof(current) - 1;
16582557Skris			while ((i = getc(fp)) != EOF && i != '\n') {
16682557Skris				if (cp < endp)
16782557Skris					*cp++ = i;
16882557Skris			}
1691553Srgrimes			*cp = '\0';
1701553Srgrimes			i = atoi(current);
17127618Simp			if (i <= 0) {
17227618Simp				ret = -1;
17327618Simp			} else {
17427618Simp				seteuid(euid);
17527618Simp				ret = kill(i, 0);
17627618Simp				seteuid(uid);
17727618Simp			}
17827618Simp			if (ret < 0) {
17931492Swollman				warn(pp);
18027618Simp			} else {
1811553Srgrimes				/* read current file name */
1821553Srgrimes				cp = current;
18382557Skris				endp = cp + sizeof(current) - 1;
18482557Skris				while ((i = getc(fp)) != EOF && i != '\n') {
18582557Skris					if (cp < endp)
18682557Skris						*cp++ = i;
18782557Skris				}
1881553Srgrimes				*cp = '\0';
1891553Srgrimes				/*
1901553Srgrimes				 * Print the status file.
1911553Srgrimes				 */
19231492Swollman				if (pp->remote)
19378300Sgad					printf("%s: ", local_host);
19427618Simp				seteuid(euid);
19531492Swollman				fd = open(pp->status_file, O_RDONLY|O_SHLOCK);
19627618Simp				seteuid(uid);
1971553Srgrimes				if (fd >= 0) {
19831492Swollman					while ((i = read(fd, line,
19931492Swollman							 sizeof(line))) > 0)
20031492Swollman						fwrite(line, 1, i, stdout);
20131492Swollman					close(fd);	/* unlocks as well */
2021553Srgrimes				} else
2031553Srgrimes					putchar('\n');
2041553Srgrimes			}
2051553Srgrimes			(void) fclose(fp);
2061553Srgrimes		}
2071553Srgrimes		/*
2081553Srgrimes		 * Now, examine the control files and print out the jobs to
2091553Srgrimes		 * be done for each user.
2101553Srgrimes		 */
2111553Srgrimes		if (!lflag)
2121553Srgrimes			header();
2131553Srgrimes		for (i = 0; i < nitems; i++) {
2141553Srgrimes			q = queue[i];
21568401Sgad			inform(pp, q->job_cfname);
2161553Srgrimes			free(q);
2171553Srgrimes		}
2181553Srgrimes		free(queue);
2191553Srgrimes	}
22031492Swollman	if (!pp->remote) {
2211553Srgrimes		if (nitems == 0)
2221553Srgrimes			puts("no entries");
2231553Srgrimes		return;
2241553Srgrimes	}
2251553Srgrimes
2261553Srgrimes	/*
2271553Srgrimes	 * Print foreign queue
2281553Srgrimes	 * Note that a file in transit may show up in either queue.
2291553Srgrimes	 */
2301553Srgrimes	if (nitems)
2311553Srgrimes		putchar('\n');
23231492Swollman	(void) snprintf(line, sizeof(line), "%c%s", format ? '\4' : '\3',
23331492Swollman			pp->remote_queue);
2341553Srgrimes	cp = line;
23527757Simp	for (i = 0; i < requests && cp-line+10 < sizeof(line) - 1; i++) {
2361553Srgrimes		cp += strlen(cp);
2371553Srgrimes		(void) sprintf(cp, " %d", requ[i]);
2381553Srgrimes	}
23922466Simp	for (i = 0; i < users && cp - line + 1 + strlen(user[i]) <
24027757Simp		sizeof(line) - 1; i++) {
2411553Srgrimes		cp += strlen(cp);
2421553Srgrimes		*cp++ = ' ';
2431553Srgrimes		(void) strcpy(cp, user[i]);
2441553Srgrimes	}
2451553Srgrimes	strcat(line, "\n");
24626844Sjoerg	savealrm = signal(SIGALRM, alarmhandler);
24731492Swollman	alarm(pp->conn_timeout);
24831492Swollman	fd = getport(pp, pp->remote_host, 0);
24931020Sjoerg	alarm(0);
25026844Sjoerg	(void)signal(SIGALRM, savealrm);
2511553Srgrimes	if (fd < 0) {
25278300Sgad		if (from_host != local_host)
25378300Sgad			printf("%s: ", local_host);
25431492Swollman		printf("connection to %s is down\n", pp->remote_host);
2551553Srgrimes	}
2561553Srgrimes	else {
2571553Srgrimes		i = strlen(line);
2581553Srgrimes		if (write(fd, line, i) != i)
25931492Swollman			fatal(pp, "Lost connection");
2601553Srgrimes		while ((i = read(fd, line, sizeof(line))) > 0)
261194859Sgad			filtered_write(line, i, stdout);
262194859Sgad		filtered_write(NULL, -1, stdout);
2631553Srgrimes		(void) close(fd);
2641553Srgrimes	}
2651553Srgrimes}
2661553Srgrimes
2671553Srgrimes/*
268194859Sgad * The lpq-info read from remote hosts may contain unprintable characters,
269194859Sgad * or carriage-returns instead of line-feeds.  Clean those up before echoing
270194859Sgad * the lpq-info line(s) to stdout.  The info may also be missing any kind of
271194859Sgad * end-of-line character.  This also turns CRLF and LFCR into a plain LF.
272194859Sgad *
273194859Sgad * This routine may be called multiple times to process a single set of
274194859Sgad * information, and after a set is finished this routine must be called
275194859Sgad * one extra time with NULL specified as the buffer address.
276194859Sgad */
277194859Sgadstatic void
278194859Sgadfiltered_write(char *wbuffer, int wlen, FILE *wstream)
279194859Sgad{
280194859Sgad	static char lastchar, savedchar;
281194859Sgad	char *chkptr, *dest_end, *dest_ch, *nxtptr, *w_end;
282194859Sgad	int destlen;
283194859Sgad	char destbuf[BUFSIZ];
284194859Sgad
285194859Sgad	if (wbuffer == NULL) {
286194859Sgad		if (savedchar != '\0') {
287194859Sgad			if (savedchar == '\r')
288194859Sgad				savedchar = '\n';
289194859Sgad			fputc(savedchar, wstream);
290194859Sgad			lastchar = savedchar;
291194859Sgad			savedchar = '\0';
292194859Sgad		}
293194859Sgad		if (lastchar != '\0' && lastchar != '\n')
294194859Sgad			fputc('\n', wstream);
295194859Sgad		lastchar = '\0';
296194859Sgad		return;
297194859Sgad	}
298194859Sgad
299194859Sgad	dest_ch = &destbuf[0];
300194859Sgad	dest_end = dest_ch + sizeof(destbuf);
301194859Sgad	chkptr = wbuffer;
302194859Sgad	w_end = wbuffer + wlen;
303194859Sgad	lastchar = '\0';
304194859Sgad	if (savedchar != '\0') {
305194859Sgad		chkptr = &savedchar;
306194859Sgad		nxtptr = wbuffer;
307194859Sgad	} else
308194859Sgad		nxtptr = chkptr + 1;
309194859Sgad
310194859Sgad	while (chkptr < w_end) {
311194859Sgad		if (nxtptr < w_end) {
312194859Sgad			if ((*chkptr == '\r' && *nxtptr == '\n') ||
313194859Sgad			    (*chkptr == '\n' && *nxtptr == '\r')) {
314194859Sgad				*dest_ch++ = '\n';
315194859Sgad				/* want to skip past that second character */
316194859Sgad				nxtptr++;
317194859Sgad				goto check_next;
318194859Sgad			}
319194859Sgad		} else {
320194859Sgad			/* This is the last byte in the buffer given on this
321194859Sgad			 * call, so check if it could be the first-byte of a
322194859Sgad			 * significant two-byte sequence.  If it is, then
323194859Sgad			 * don't write it out now, but save for checking in
324194859Sgad			 * the next call.
325194859Sgad			 */
326194859Sgad			savedchar = '\0';
327194859Sgad			if (*chkptr == '\r' || *chkptr == '\n') {
328194859Sgad				savedchar = *chkptr;
329194859Sgad				break;
330194859Sgad			}
331194859Sgad		}
332194859Sgad		if (*chkptr == '\r')
333194859Sgad			*dest_ch++ = '\n';
334194859Sgad#if 0		/* XXX - don't translate unprintable characters (yet) */
335194859Sgad		else if (*chkptr != '\t' && *chkptr != '\n' &&
336194859Sgad		    !isprintch(*chkptr))
337194859Sgad			*dest_ch++ = '?';
338194859Sgad#endif
339194859Sgad		else
340194859Sgad			*dest_ch++ = *chkptr;
341194859Sgad
342194859Sgadcheck_next:
343194859Sgad		chkptr = nxtptr;
344194859Sgad		nxtptr = chkptr + 1;
345194859Sgad		if (dest_ch >= dest_end) {
346194859Sgad			destlen = dest_ch - &destbuf[0];
347194859Sgad			fwrite(destbuf, 1, destlen, wstream);
348194859Sgad			lastchar = destbuf[destlen - 1];
349194859Sgad			dest_ch = &destbuf[0];
350194859Sgad		}
351194859Sgad	}
352194859Sgad	destlen = dest_ch - &destbuf[0];
353194859Sgad	if (destlen > 0) {
354194859Sgad		fwrite(destbuf, 1, destlen, wstream);
355194859Sgad		lastchar = destbuf[destlen - 1];
356194859Sgad	}
357194859Sgad}
358194859Sgad
359194859Sgad/*
3601553Srgrimes * Print a warning message if there is no daemon present.
3611553Srgrimes */
36228621Sjoergstatic void
36378146Sgadwarn(const struct printer *pp)
3641553Srgrimes{
36531492Swollman	if (pp->remote)
36678300Sgad		printf("%s: ", local_host);
3671553Srgrimes	puts("Warning: no daemon present");
3681553Srgrimes	current[0] = '\0';
3691553Srgrimes}
3701553Srgrimes
3711553Srgrimes/*
3721553Srgrimes * Print the header for the short listing format
3731553Srgrimes */
3741553Srgrimesvoid
37578146Sgadheader(void)
3761553Srgrimes{
37779739Sgad	printf("%s", head0);
3781553Srgrimes	col = strlen(head0)+1;
3791553Srgrimes	blankfill(SIZCOL);
38079739Sgad	printf("%s", head1);
3811553Srgrimes}
3821553Srgrimes
3831553Srgrimesvoid
38478146Sgadinform(const struct printer *pp, char *cf)
3851553Srgrimes{
386139464Sgad	int copycnt, jnum;
38768100Sgad	char	 savedname[MAXPATHLEN+1];
38868100Sgad	FILE	*cfp;
3891553Srgrimes
3901553Srgrimes	/*
3911553Srgrimes	 * There's a chance the control file has gone away
3921553Srgrimes	 * in the meantime; if this is the case just keep going
3931553Srgrimes	 */
39427618Simp	seteuid(euid);
3951553Srgrimes	if ((cfp = fopen(cf, "r")) == NULL)
3961553Srgrimes		return;
39727618Simp	seteuid(uid);
3981553Srgrimes
3991553Srgrimes	if (rank < 0)
4001553Srgrimes		rank = 0;
40131492Swollman	if (pp->remote || garbage || strcmp(cf, current))
4021553Srgrimes		rank++;
40368100Sgad
40468100Sgad	/*
40568100Sgad	 * The cf-file may include commands to print more than one datafile
40668100Sgad	 * from the user.  For each datafile, the cf-file contains at least
40768100Sgad	 * one line which starts with some format-specifier ('a'-'z'), and
40868100Sgad	 * a second line ('N'ame) which indicates the original name the user
40968100Sgad	 * specified for that file.  There can be multiple format-spec lines
41068100Sgad	 * for a single Name-line, if the user requested multiple copies of
41168100Sgad	 * that file.  Standard lpr puts the format-spec line(s) before the
41268100Sgad	 * Name-line, while lprNG puts the Name-line before the format-spec
41368100Sgad	 * line(s).  This section needs to handle the lines in either order.
41468100Sgad	 */
41568100Sgad	copycnt = 0;
41668100Sgad	file[0] = '\0';
41768100Sgad	savedname[0] = '\0';
418139464Sgad	jnum = calc_jobnum(cf, NULL);
4191553Srgrimes	while (getline(cfp)) {
4201553Srgrimes		switch (line[0]) {
4211553Srgrimes		case 'P': /* Was this file specified in the user's list? */
4221553Srgrimes			if (!inlist(line+1, cf)) {
4231553Srgrimes				fclose(cfp);
4241553Srgrimes				return;
4251553Srgrimes			}
4261553Srgrimes			if (lflag) {
4271553Srgrimes				printf("\n%s: ", line+1);
4281553Srgrimes				col = strlen(line+1) + 2;
4291553Srgrimes				prank(rank);
4301553Srgrimes				blankfill(JOBCOL);
4311553Srgrimes				printf(" [job %s]\n", cf+3);
4321553Srgrimes			} else {
4331553Srgrimes				col = 0;
4341553Srgrimes				prank(rank);
4351553Srgrimes				blankfill(OWNCOL);
436139464Sgad				printf("%-10s %-3d  ", line+1, jnum);
4371553Srgrimes				col += 16;
4381553Srgrimes				first = 1;
4391553Srgrimes			}
4401553Srgrimes			continue;
4411553Srgrimes		default: /* some format specifer and file name? */
4421553Srgrimes			if (line[0] < 'a' || line[0] > 'z')
44368100Sgad				break;
44468100Sgad			if (copycnt == 0 || strcmp(file, line+1) != 0) {
44580133Sgad				strlcpy(file, line + 1, sizeof(file));
44622466Simp			}
44768100Sgad			copycnt++;
44868100Sgad			/*
44968100Sgad			 * deliberately 'continue' to another getline(), so
45068100Sgad			 * all format-spec lines for this datafile are read
45168100Sgad			 * in and counted before calling show()
45268100Sgad			 */
4531553Srgrimes			continue;
4541553Srgrimes		case 'N':
45580133Sgad			strlcpy(savedname, line + 1, sizeof(savedname));
45668100Sgad			break;
45768100Sgad		}
45868100Sgad		if ((file[0] != '\0') && (savedname[0] != '\0')) {
45968100Sgad			show(savedname, file, copycnt);
46068100Sgad			copycnt = 0;
4611553Srgrimes			file[0] = '\0';
46268100Sgad			savedname[0] = '\0';
4631553Srgrimes		}
4641553Srgrimes	}
4651553Srgrimes	fclose(cfp);
46668100Sgad	/* check for a file which hasn't been shown yet */
46768100Sgad	if (file[0] != '\0') {
46868100Sgad		if (savedname[0] == '\0') {
46968100Sgad			/* a safeguard in case the N-ame line is missing */
47080133Sgad			strlcpy(savedname, file, sizeof(savedname));
47168100Sgad		}
47268100Sgad		show(savedname, file, copycnt);
47368100Sgad	}
4741553Srgrimes	if (!lflag) {
4751553Srgrimes		blankfill(SIZCOL);
4761553Srgrimes		printf("%ld bytes\n", totsize);
4771553Srgrimes		totsize = 0;
4781553Srgrimes	}
4791553Srgrimes}
4801553Srgrimes
4811553Srgrimesint
48278146Sgadinlist(char *uname, char *cfile)
4831553Srgrimes{
484139464Sgad	int *r, jnum;
485139464Sgad	char **u;
486139464Sgad	const char *cfhost;
4871553Srgrimes
4881553Srgrimes	if (users == 0 && requests == 0)
4891553Srgrimes		return(1);
4901553Srgrimes	/*
4911553Srgrimes	 * Check to see if it's in the user list
4921553Srgrimes	 */
4931553Srgrimes	for (u = user; u < &user[users]; u++)
49478146Sgad		if (!strcmp(*u, uname))
4951553Srgrimes			return(1);
4961553Srgrimes	/*
4971553Srgrimes	 * Check the request list
4981553Srgrimes	 */
499139464Sgad	jnum = calc_jobnum(cfile, &cfhost);
5001553Srgrimes	for (r = requ; r < &requ[requests]; r++)
501139464Sgad		if (*r == jnum && !strcmp(cfhost, from_host))
5021553Srgrimes			return(1);
5031553Srgrimes	return(0);
5041553Srgrimes}
5051553Srgrimes
5061553Srgrimesvoid
50778146Sgadshow(const char *nfile, const char *datafile, int copies)
5081553Srgrimes{
5091553Srgrimes	if (strcmp(nfile, " ") == 0)
5101553Srgrimes		nfile = "(standard input)";
5111553Srgrimes	if (lflag)
51278146Sgad		ldump(nfile, datafile, copies);
5131553Srgrimes	else
51478146Sgad		dump(nfile, datafile, copies);
5151553Srgrimes}
5161553Srgrimes
5171553Srgrimes/*
5181553Srgrimes * Fill the line with blanks to the specified column
5191553Srgrimes */
5201553Srgrimesvoid
52178146Sgadblankfill(int tocol)
5221553Srgrimes{
52378146Sgad	while (col++ < tocol)
5241553Srgrimes		putchar(' ');
5251553Srgrimes}
5261553Srgrimes
5271553Srgrimes/*
5281553Srgrimes * Give the abbreviated dump of the file names
5291553Srgrimes */
5301553Srgrimesvoid
53178146Sgaddump(const char *nfile, const char *datafile, int copies)
5321553Srgrimes{
5331553Srgrimes	struct stat lbuf;
53468101Sgad	const char etctmpl[] = ", ...";
53568101Sgad	char	 etc[sizeof(etctmpl)];
53668101Sgad	char	*lastsep;
53768101Sgad	short	 fill, nlen;
53868101Sgad	short	 rem, remetc;
5391553Srgrimes
5401553Srgrimes	/*
54168101Sgad	 * Print as many filenames as will fit
54268101Sgad	 *      (leaving room for the 'total size' field)
5431553Srgrimes	 */
54468101Sgad	fill = first ? 0 : 2;	/* fill space for ``, '' */
54568101Sgad	nlen = strlen(nfile);
54668101Sgad	rem = SIZCOL - 1 - col;
54768101Sgad	if (nlen + fill > rem) {
54868101Sgad		if (first) {
54968101Sgad			/* print the right-most part of the name */
55068101Sgad			printf("...%s ", &nfile[3+nlen-rem]);
55168101Sgad			col = SIZCOL;
55268101Sgad		} else if (rem > 0) {
55368101Sgad			/* fit as much of the etc-string as we can */
55468101Sgad			remetc = rem;
55568101Sgad			if (rem > strlen(etctmpl))
55668101Sgad				remetc = strlen(etctmpl);
55768101Sgad			etc[0] = '\0';
55868101Sgad			strncat(etc, etctmpl, remetc);
55979739Sgad			printf("%s", etc);
56068101Sgad			col += remetc;
56168101Sgad			rem -= remetc;
56268101Sgad			/* room for the last segment of this filename? */
56368101Sgad			lastsep = strrchr(nfile, '/');
56468101Sgad			if ((lastsep != NULL) && (rem > strlen(lastsep))) {
56568101Sgad				/* print the right-most part of this name */
56668101Sgad				printf("%s", lastsep);
56768101Sgad				col += strlen(lastsep);
56868101Sgad			} else {
56968101Sgad				/* do not pack any more names in here */
57068101Sgad				blankfill(SIZCOL);
57168101Sgad			}
5721553Srgrimes		}
5731553Srgrimes	} else {
57468101Sgad		if (!first)
5751553Srgrimes			printf(", ");
5761553Srgrimes		printf("%s", nfile);
57768101Sgad		col += nlen + fill;
5781553Srgrimes	}
57968101Sgad	first = 0;
58068101Sgad
58127618Simp	seteuid(euid);
58278146Sgad	if (*datafile && !stat(datafile, &lbuf))
5831553Srgrimes		totsize += copies * lbuf.st_size;
58427618Simp	seteuid(uid);
5851553Srgrimes}
5861553Srgrimes
5871553Srgrimes/*
5881553Srgrimes * Print the long info about the file
5891553Srgrimes */
5901553Srgrimesvoid
59178146Sgadldump(const char *nfile, const char *datafile, int copies)
5921553Srgrimes{
5931553Srgrimes	struct stat lbuf;
5941553Srgrimes
5951553Srgrimes	putchar('\t');
5961553Srgrimes	if (copies > 1)
5971553Srgrimes		printf("%-2d copies of %-19s", copies, nfile);
5981553Srgrimes	else
5991553Srgrimes		printf("%-32s", nfile);
60078146Sgad	if (*datafile && !stat(datafile, &lbuf))
60135998Sjb		printf(" %qd bytes", (long long) lbuf.st_size);
6021553Srgrimes	else
6031553Srgrimes		printf(" ??? bytes");
6041553Srgrimes	putchar('\n');
6051553Srgrimes}
6061553Srgrimes
6071553Srgrimes/*
6081553Srgrimes * Print the job's rank in the queue,
6091553Srgrimes *   update col for screen management
6101553Srgrimes */
6111553Srgrimesvoid
61278146Sgadprank(int n)
6131553Srgrimes{
6141553Srgrimes	char rline[100];
61578146Sgad	static const char *r[] = {
6161553Srgrimes		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
6171553Srgrimes	};
6181553Srgrimes
6191553Srgrimes	if (n == 0) {
6201553Srgrimes		printf("active");
6211553Srgrimes		col += 6;
6221553Srgrimes		return;
6231553Srgrimes	}
6241553Srgrimes	if ((n/10)%10 == 1)
6251553Srgrimes		(void)snprintf(rline, sizeof(rline), "%dth", n);
6261553Srgrimes	else
6271553Srgrimes		(void)snprintf(rline, sizeof(rline), "%d%s", n, r[n%10]);
6281553Srgrimes	col += strlen(rline);
6291553Srgrimes	printf("%s", rline);
6301553Srgrimes}
63126844Sjoerg
63226844Sjoergvoid
63378146Sgadalarmhandler(int signo __unused)
63426844Sjoerg{
63578146Sgad	/* the signal is ignored */
63678146Sgad	/* (the '__unused' is just to avoid a compile-time warning) */
63726844Sjoerg}
638