1 /*	displayq.c	4.2	83/05/13	*/
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 	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();
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 (nitems == 0) {
109 		if (sendtorem)
110 			printf("\n%s: ", host);
111 		printf("no entries\n");
112 		return(0);
113 	}
114 	fp = fopen(LO, "r");
115 	if (fp == NULL || flock(fileno(fp), FSHLOCK|FNBLOCK) == 0) {
116 		if (fp != NULL)
117 			fclose(fp);
118 		garbage = nitems;
119 		if (stat(LO, &statb) >= 0 && (statb.st_mode & 0100))
120 			printf("Warning: %s is down\n", printer);
121 		else
122 			printf("Warning: no daemon present\n");
123 	} else {
124 		register char *cp = current;
125 
126 		/* skip daemon pid */
127 		while ((*cp = getc(fp)) != EOF && *cp != '\n');
128 		/* read current file name */
129 		while ((*cp = getc(fp)) != EOF && *cp != '\n')
130 			cp++;
131 		*cp = '\0';
132 		fclose(fp);
133 		/*
134 		 * Print the status file to show what the daemon is doing.
135 		 */
136 		if (sendtorem)
137 			printf("\n%s: ", host);
138 		if ((fd = open(ST, FRDONLY|FSHLOCK)) >= 0) {
139 			while ((i = read(fd, line, sizeof(line))) > 0)
140 				(void) fwrite(line, 1, i, stdout);
141 			(void) close(fd);
142 		} else
143 			putchar('\n');
144 	}
145 	/*
146 	 * Now, examine the control files and print out the jobs to
147 	 * be done for each user.
148 	 */
149 	if (!lflag)
150 		header();
151 	for (i = 0; i < nitems; i++) {
152 		q = queue[i];
153 		inform(q->q_name);
154 		free(q);
155 	}
156 	free(queue);
157 	return(nitems-garbage);
158 }
159 
160 /*
161  * Print the header for the short listing format
162  */
163 header()
164 {
165 	printf(head0);
166 	col = strlen(head0)+1;
167 	blankfill(SIZCOL);
168 	printf(head1);
169 }
170 
171 inform(cf)
172 	char *cf;
173 {
174 	register int j, k;
175 	register char *cp;
176 	FILE *cfp;
177 
178 	/*
179 	 * There's a chance the control file has gone away
180 	 * in the meantime; if this is the case just keep going
181 	 */
182 	if ((cfp = fopen(cf, "r")) == NULL)
183 		return;
184 
185 	if (rank < 0)
186 		rank = 0;
187 	if (sendtorem || garbage || strcmp(cf, current))
188 		rank++;
189 	j = 0;
190 	while (getline(cfp)) {
191 		switch (line[0]) {
192 		case 'P': /* Was this file specified in the user's list? */
193 			if (!inlist(line+1, cf)) {
194 				fclose(cfp);
195 				return;
196 			}
197 			if (lflag) {
198 				printf("\n%s: ", line+1);
199 				col = strlen(line+1) + 2;
200 				prank(rank);
201 				blankfill(JOBCOL);
202 				printf(" [job %s]\n", cf+3);
203 			} else {
204 				col = 0;
205 				prank(rank);
206 				blankfill(OWNCOL);
207 				printf("%-10s %-3d  ", line+1, atoi(cf+3));
208 				col += 16;
209 				first = 1;
210 			}
211 			continue;
212 		default: /* some format specifer and file name? */
213 			if (line[0] < 'a' || line[0] > 'z')
214 				continue;
215 			if (j == 0 || strcmp(file, line+1) != 0)
216 				strcpy(file, line+1);
217 			j++;
218 			continue;
219 		case 'N':
220 			show(line+1, file, j);
221 			file[0] = '\0';
222 			j = 0;
223 		}
224 	}
225 	fclose(cfp);
226 	if (!lflag) {
227 		blankfill(SIZCOL);
228 		printf("%D bytes\n", totsize);
229 		totsize = 0;
230 	}
231 }
232 
233 inlist(name, file)
234 	char *name, *file;
235 {
236 	register int *r, n;
237 	register char **u, *cp;
238 
239 	if (users == 0 && requests == 0)
240 		return(1);
241 	/*
242 	 * Check to see if it's in the user list
243 	 */
244 	for (u = user; u < &user[users]; u++)
245 		if (!strcmp(*u, name))
246 			return(1);
247 	/*
248 	 * Check the request list
249 	 */
250 	for (n = 0, cp = file+3; isdigit(*cp); )
251 		n = n * 10 + (*cp++ - '0');
252 	for (r = requ; r < &requ[requests]; r++)
253 		if (*r == n && !strcmp(cp, from))
254 			return(1);
255 	return(0);
256 }
257 
258 show(nfile, file, copies)
259 	register char *nfile, *file;
260 {
261 	if (strcmp(nfile, " ") == 0)
262 		nfile = "(standard input)";
263 	if (lflag)
264 		ldump(nfile, file, copies);
265 	else
266 		dump(nfile, file, copies);
267 }
268 
269 /*
270  * Fill the line with blanks to the specified column
271  */
272 blankfill(n)
273 	register int n;
274 {
275 	while (col++ < n)
276 		putchar(' ');
277 }
278 
279 /*
280  * Give the abbreviated dump of the file names
281  */
282 dump(nfile, file, copies)
283 	char *nfile, *file;
284 {
285 	register short n, fill;
286 	struct stat lbuf;
287 
288 	/*
289 	 * Print as many files as will fit
290 	 *  (leaving room for the total size)
291 	 */
292 	 fill = first ? 0 : 2;	/* fill space for ``, '' */
293 	 if (((n = strlen(nfile)) + col + fill) >= SIZCOL-4) {
294 		if (col < SIZCOL) {
295 			printf(" ..."), col += 4;
296 			blankfill(SIZCOL);
297 		}
298 	} else {
299 		if (first)
300 			first = 0;
301 		else
302 			printf(", ");
303 		printf("%s", nfile);
304 		col += n+fill;
305 	}
306 	if (*file && !stat(file, &lbuf))
307 		totsize += copies * lbuf.st_size;
308 }
309 
310 /*
311  * Print the long info about the file
312  */
313 ldump(nfile, file, copies)
314 	char *nfile, *file;
315 {
316 	struct stat lbuf;
317 
318 	putchar('\t');
319 	if (copies > 1)
320 		printf("%-2d copies of %-19s", copies, nfile);
321 	else
322 		printf("%-32s", nfile);
323 	if (*file && !stat(file, &lbuf))
324 		printf(" %D bytes", lbuf.st_size);
325 	else
326 		printf(" ??? bytes");
327 	putchar('\n');
328 }
329 
330 /*
331  * Print the job's rank in the queue,
332  *   update col for screen management
333  */
334 prank(n)
335 {
336 	char line[100];
337 	static char *r[] = {
338 		"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
339 	};
340 
341 	if (n == 0) {
342 		printf("active");
343 		col += 6;
344 		return;
345 	}
346 	if ((n/10) == 1)
347 		(void) sprintf(line, "%dth", n);
348 	else
349 		(void) sprintf(line, "%d%s", n, r[n%10]);
350 	col += strlen(line);
351 	printf("%s", line);
352 }
353