1 /*	displayq.c	4.1	83/04/29	*/
2 /*
3  * Routines to display the state of the queue.
4  */
5 
6 #include "lp.h"
7 
8 #define	JOBCOL		40	/* column for job # in -l format */
9 #define OWNCOL		7	/* start of Owner column in normal */
10 
11 /*
12  * Stuff for handling job specifications
13  */
14 extern char	*user[];	/* users to process */
15 extern int	users;		/* # of users in user array */
16 extern int	requ[];		/* job number of spool entries */
17 extern int	requests;	/* # of spool requests */
18 
19 int	lflag;			/* long output option */
20 char	current[40];		/* current file being printed */
21 int	garbage;		/* # of garbage cf files */
22 int	rank;			/* order to be printed (-1=none, 0=active) */
23 long	totsize;		/* total print job size in bytes */
24 int	first;			/* first file in ``files'' column? */
25 int	col;			/* column on screen */
26 int	SIZCOL = 62;		/* start of Size column in normal */
27 int	sendtorem;		/* are we sending to a remote? */
28 char	file[132];		/* print file name */
29 
30 char	*head0 = "Rank   Owner      Job  Files";
31 char	*head1 = "Total Size\n";
32 
33 /*
34  * Display the current state of the queue. Format = 1 if long format.
35  */
36 displayq(format)
37 	int format;
38 {
39 	register struct queue *q;
40 	register int i, nitems, fd;
41 	struct queue **queue;
42 	struct stat statb;
43 	FILE *fp;
44 
45 	name = "displayq";
46 	lflag = format;
47 	totsize = 0;
48 	rank = -1;
49 
50 	if ((i = pgetent(line, printer)) < 0)
51 		fatal("cannot open printer description file");
52 	else if (i == 0)
53 		fatal("unknown printer");
54 	if ((LP = pgetstr("lp", &bp)) == NULL)
55 		LP = DEFDEVLP;
56 	if ((RP = pgetstr("rp", &bp)) == NULL)
57 		RP = printer;
58 	if ((SD = pgetstr("sd", &bp)) == NULL)
59 		SD = DEFSPOOL;
60 	if ((LO = pgetstr("lo", &bp)) == NULL)
61 		LO = DEFLOCK;
62 	if ((ST = pgetstr("st", &bp)) == NULL)
63 		ST = DEFSTAT;
64 	RM = pgetstr("rm", &bp);
65 
66 	/*
67 	 * If there is no local printer, then print the queue on
68 	 * the remote machine and then what's in the queue here.
69 	 * Note that a file in transit may not show up in either queue.
70 	 */
71 	if (*LP == '\0') {
72 		register char *cp;
73 		char c;
74 
75 		sendtorem++;
76 		(void) sprintf(line, "%c%s", format + '\3', RP);
77 		cp = line;
78 		for (i = 0; i < requests; i++) {
79 			cp += strlen(cp);
80 			(void) sprintf(cp, " %d", requ[i]);
81 		}
82 		for (i = 0; i < users; i++) {
83 			cp += strlen(cp);
84 			*cp++ = ' ';
85 			strcpy(cp, user[i]);
86 		}
87 		strcat(line, "\n");
88 		fd = getport();
89 		if (fd < 0) {
90 			if (from != host)
91 				printf("%s: ", host);
92 			printf("connection to %s is down\n", RM);
93 		} else {
94 			i = strlen(line);
95 			if (write(fd, line, i) != i)
96 				fatal("Lost connection");
97 			while ((i = read(fd, line, sizeof(line))) > 0)
98 				(void) fwrite(line, 1, i, stdout);
99 			(void) close(fd);
100 		}
101 	}
102 	/*
103 	 * Find all the control files in the spooling directory
104 	 */
105 	if (chdir(SD) < 0)
106 		fatal("cannot chdir to spooling directory");
107 	if ((nitems = getq(&queue)) < 0)
108 		fatal("cannot examine spooling area\n");
109 	if (nitems == 0) {
110 		if (sendtorem)
111 			printf("\n%s: ", host);
112 		printf("no entries\n");
113 		return(0);
114 	}
115 	fp = fopen(LO, "r");
116 	if (fp == NULL || flock(fileno(fp), FSHLOCK|FNBLOCK) == 0) {
117 		if (fp != NULL)
118 			fclose(fp);
119 		garbage = nitems;
120 		if (*LP && stat(LP, &statb) >= 0 && (statb.st_mode & 0777) == 0)
121 			status("Warning: %s is down", printer);
122 		else
123 			status("Warning: no daemon present");
124 	} else {
125 		register char *cp = current;
126 
127 		/* skip daemon pid */
128 		while ((*cp = getc(fp)) != EOF && *cp != '\n');
129 		/* read current file name */
130 		while ((*cp = getc(fp)) != EOF && *cp != '\n')
131 			cp++;
132 		*cp = '\0';
133 		fclose(fp);
134 	}
135 	/*
136 	 * Now, examine the control files and print out the jobs to
137 	 * be done for each user.
138 	 */
139 	if (sendtorem)
140 		printf("\n%s: ", host);
141 	if ((fd = open(ST, FRDONLY|FSHLOCK)) >= 0) {
142 		while ((i = read(fd, line, sizeof(line))) > 0)
143 			(void) fwrite(line, 1, i, stdout);
144 		(void) close(fd);
145 	} else
146 		putchar('\n');
147 	if (!lflag)
148 		header();
149 	for (i = 0; i < nitems; i++) {
150 		q = queue[i];
151 		inform(q->q_name);
152 		free(q);
153 	}
154 	free(queue);
155 	return(nitems-garbage);
156 }
157 
158 /*
159  * Print the header for the short listing format
160  */
161 header()
162 {
163 	printf(head0);
164 	col = strlen(head0)+1;
165 	blankfill(SIZCOL);
166 	printf(head1);
167 }
168 
169 inform(cf)
170 	char *cf;
171 {
172 	register int j, k;
173 	register char *cp;
174 	FILE *cfp;
175 
176 	/*
177 	 * There's a chance the control file has gone away
178 	 * in the meantime; if this is the case just keep going
179 	 */
180 	if ((cfp = fopen(cf, "r")) == NULL)
181 		return;
182 
183 	if (rank < 0)
184 		rank = 0;
185 	if (sendtorem || garbage || strcmp(cf, current))
186 		rank++;
187 	j = 0;
188 	while (getline(cfp)) {
189 		switch (line[0]) {
190 		case 'P': /* Was this file specified in the user's list? */
191 			if (!inlist(line+1, cf)) {
192 				fclose(cfp);
193 				return;
194 			}
195 			if (lflag) {
196 				printf("\n%s: ", line+1);
197 				col = strlen(line+1) + 2;
198 				prank(rank);
199 				blankfill(JOBCOL);
200 				printf(" [job %s]\n", cf+3);
201 			} else {
202 				col = 0;
203 				prank(rank);
204 				blankfill(OWNCOL);
205 				printf("%-10s %-3d  ", line+1, atoi(cf+3));
206 				col += 16;
207 				first = 1;
208 			}
209 			continue;
210 		default: /* some format specifer and file name? */
211 			if (line[0] < 'a' || line[0] > 'z')
212 				continue;
213 			if (j == 0 || strcmp(file, line+1) != 0)
214 				strcpy(file, line+1);
215 			j++;
216 			continue;
217 		case 'N':
218 			show(line+1, file, j);
219 			file[0] = '\0';
220 			j = 0;
221 		}
222 	}
223 	fclose(cfp);
224 	if (!lflag) {
225 		blankfill(SIZCOL);
226 		printf("%D bytes\n", totsize);
227 		totsize = 0;
228 	}
229 }
230 
231 inlist(name, file)
232 	char *name, *file;
233 {
234 	register int *r, n;
235 	register char **u, *cp;
236 
237 	if (users == 0 && requests == 0)
238 		return(1);
239 	/*
240 	 * Check to see if it's in the user list
241 	 */
242 	for (u = user; u < &user[users]; u++)
243 		if (!strcmp(*u, name))
244 			return(1);
245 	/*
246 	 * Check the request list
247 	 */
248 	for (n = 0, cp = file+3; isdigit(*cp); )
249 		n = n * 10 + (*cp++ - '0');
250 	for (r = requ; r < &requ[requests]; r++)
251 		if (*r == n && !strcmp(cp, from))
252 			return(1);
253 	return(0);
254 }
255 
256 show(nfile, file, copies)
257 	register char *nfile, *file;
258 {
259 	if (strcmp(nfile, " ") == 0)
260 		nfile = "(standard input)";
261 	if (lflag)
262 		ldump(nfile, file, copies);
263 	else
264 		dump(nfile, file, copies);
265 }
266 
267 /*
268  * Fill the line with blanks to the specified column
269  */
270 blankfill(n)
271 	register int n;
272 {
273 	while (col++ < n)
274 		putchar(' ');
275 }
276 
277 /*
278  * Give the abbreviated dump of the file names
279  */
280 dump(nfile, file, copies)
281 	char *nfile, *file;
282 {
283 	register short n, fill;
284 	struct stat lbuf;
285 
286 	/*
287 	 * Print as many files as will fit
288 	 *  (leaving room for the total size)
289 	 */
290 	 fill = first ? 0 : 2;	/* fill space for ``, '' */
291 	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
292 		if (col < SIZCOL) {
293 			printf(" ..."), col += 4;
294 			blankfill(SIZCOL);
295 		}
296 	} else {
297 		if (first)
298 			first = 0;
299 		else
300 			printf(", ");
301 		printf("%s", nfile);
302 		col += n+fill;
303 	}
304 	if (*file && !stat(file, &lbuf))
305 		totsize += copies * lbuf.st_size;
306 }
307 
308 /*
309  * Print the long info about the file
310  */
311 ldump(nfile, file, copies)
312 	char *nfile, *file;
313 {
314 	struct stat lbuf;
315 
316 	putchar('\t');
317 	if (copies > 1)
318 		printf("%-2d copies of %-19s", copies, nfile);
319 	else
320 		printf("%-32s", nfile);
321 	if (*file && !stat(file, &lbuf))
322 		printf(" %D bytes", lbuf.st_size);
323 	else
324 		printf(" ??? bytes");
325 	putchar('\n');
326 }
327 
328 /*
329  * Print the job's rank in the queue,
330  *   update col for screen management
331  */
332 prank(n)
333 {
334 	char line[100];
335 	static char *r[] = {
336 		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
337 	};
338 
339 	if (n == 0) {
340 		printf("active");
341 		col += 6;
342 		return;
343 	}
344 	if ((n/10) == 1)
345 		(void) sprintf(line, "%dth", n);
346 	else
347 		(void) sprintf(line, "%d%s", n, r[n%10]);
348 	col += strlen(line);
349 	printf("%s", line);
350 }
351