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