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