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