1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/***************************************************************************
18 * LPRng - An Extended Print Spooler System
19 *
20 * Copyright 1988-2003, Patrick Powell, San Diego, CA
21 *     papowell@lprng.com
22 * See LICENSE for conditions of use.
23 *
24 ***************************************************************************/
25
26 static char *const _id =
27"$Id: lpd_status.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $";
28
29
30#include "lp.h"
31#include "getopt.h"
32#include "gethostinfo.h"
33#include "proctitle.h"
34#include "getprinter.h"
35#include "getqueue.h"
36#include "child.h"
37#include "fileopen.h"
38#include "sendreq.h"
39#include "globmatch.h"
40#include "permission.h"
41#include "lockfile.h"
42#include "errorcodes.h"
43
44#include "lpd_jobs.h"
45#include "lpd_status.h"
46
47//extern char printerstatus[32];//JY1106
48
49/**** ENDINCLUDE ****/
50
51/***************************************************************************
52 * Commentary:
53 * Patrick Powell Tue May  2 09:32:50 PDT 1995
54 *
55 * Return status:
56 * 	status has two formats: short and long
57 *
58 * Status information is obtained from 3 places:
59 * 1. The status file
60 * 2. any additional progress files indicated in the status file
61 * 3. job queue
62 *
63 * The status file is maintained by the current unspooler process.
64 * It updates this file with the following information:
65 *
66 * PID of the unspooler process   [line 1]
67 * active job and  status file name
68 * active job and  status file name
69 *
70 * Example 1:
71 * 3012
72 * cfa1024host status
73 *
74 * Example 2:
75 * 3015
76 * cfa1024host statusfd2
77 * cfa1026host statusfd1
78 *
79 * Format of the information reporting:
80 *
81 * 0        1         2         3         4         5         6         7
82 * 12345678901234567890123456789012345678901234567890123456789012345678901234
83 *  Rank   Owner/ID                   Class Job  Files               Size Time
84 * 1      papowell@astart4+322          A  322 /tmp/hi                3 17:33:47
85 * x     Sx                           SxSx    Sx                 Sx    Sx       X
86 *
87 ***************************************************************************/
88
89#define RANKW 7
90#define OWNERW 29
91#define CLASSW 2
92#define JOBW 6
93#define FILEW 18
94#define SIZEW 6
95#define TIMEW 8
96
97
98int Job_status( int *sock, char *input )
99{
100	char *s, *t, *name, *hash_key;
101	int displayformat, status_lines = 0, i, n;
102	struct line_list l, listv;
103	struct line_list done_list;
104	char error[SMALLBUFFER], buffer[16];
105	int db, dbflag;
106
107	FILE *READSTATUSFILE;//JY1120
108	char readbuffer[SMALLBUFFER];//JY1120
109	char *str_index;//JY1120
110
111#if !defined(JYWENG20031104status)
112	if( input && *input ) ++input;//JY1114
113	if(get_queue_name(input))
114	{
115		printf("QueueName is not LPRServer\n");
116		send_ack_packet(sock, ACK_FAIL);//JY1120
117		return(0);
118	}
119	else
120		printf("QueueName is LPRServer\n");
121
122	int prnstatus=1;
123	char buffertosend[LARGEBUFFER];
124	int fdPRNPARorUSB=0;/*JYWENG20031104*/
125	if((check_par_usb_prn())== 1)
126		fdPRNPARorUSB=open("/dev/usb/lp0",O_RDWR);
127	else
128		fdPRNPARorUSB=open("/dev/lp0",O_RDWR);
129
130	if(fdPRNPARorUSB == 0)
131	{
132		printf("file descriptor not created\n");
133		send_ack_packet(sock, ACK_FAIL);//JY1120
134		return(0);
135	}
136//	ioctl(fdPRNPARorUSB, 0x060b, &prnstatus);
137//	if(prnstatus == 0)
138//JY1120
139	if((READSTATUSFILE=fopen("/var/state/printstatus.txt", "r")) == NULL)
140	{
141		printf("open /var/state/printstatus.txt failed!\n");
142		send_ack_packet(sock, ACK_FAIL);//JY1120
143		return(0);
144	}
145	while( fgets(readbuffer, SMALLBUFFER, READSTATUSFILE) != NULL)
146	{
147		if((str_index = strstr(readbuffer, "PRINTER_STATUS=\"")))
148		{
149			str_index += 16;//moving to status
150			strncpy(printerstatus, str_index, strlen(str_index) - 2 );
151		}
152	}
153//JY1120
154
155	SNPRINTF(buffertosend, sizeof(buffertosend))"Status: %s\n", printerstatus);
156//	else
157//		SNPRINTF(buffertosend, sizeof(buffertosend))"Status: Off line\n");
158//	if( Write_fd_str( *sock, buffertosend ) < 0 ) cleanup(0);
159	if( write( *sock, buffertosend, strlen(buffertosend) ) < 0 ) cleanup(0);
160	exit(0);//JY1120
161
162#endif
163
164
165#ifdef REMOVE
166	Init_line_list(&l);
167	Init_line_list(&listv);
168	Init_line_list(&done_list);
169	db = Debug;
170	dbflag = DbgFlag;
171
172	Name = "Job_status";
173
174	/* get the format */
175	if( (s = safestrchr(input, '\n' )) ) *s = 0;
176	displayformat = *input++;
177
178	/*
179	 * if we get a short/long request from these hosts,
180	 * reverse the sense of question
181	 */
182	if( Reverse_lpq_status_DYN
183		&& (displayformat == REQ_DSHORT || displayformat==REQ_DLONG)  ){
184		Free_line_list(&l);
185		Split(&l,Reverse_lpq_status_DYN,File_sep,0,0,0,0,0,0);
186		if( Match_ipaddr_value( &l, &RemoteHost_IP ) == 0 ){
187			DEBUGF(DLPQ1)("Job_status: reversing status sense");
188			if( displayformat == REQ_DSHORT ){
189				displayformat = REQ_DLONG;
190			} else {
191				displayformat = REQ_DSHORT;
192			}
193		}
194		Free_line_list(&l);
195	}
196	/*
197	 * we have a list of hosts with format of the form:
198	 *  Key=list; Key=list;...
199	 *  key is s for short, l for long
200	 */
201	DEBUGF(DLPQ1)("Job_status: Force_lpq_status_DYN '%s'", Force_lpq_status_DYN);
202	if( Force_lpq_status_DYN ){
203		Free_line_list(&listv);
204		Split(&listv,Force_lpq_status_DYN,";",0,0,0,0,0,0);
205		for(i = 0; i < listv.count; ++i ){
206			s = listv.list[i];
207			if( (t = safestrpbrk(s,File_sep)) ) *t++ = 0;
208			Free_line_list(&l);
209			Split(&l,t,Value_sep,0,0,0,0,0,0);
210			DEBUGF(DLPQ1)("Job_status: Force_lpq_status '%s'='%s'", s,t);
211			if( Match_ipaddr_value( &l, &RemoteHost_IP ) == 0 ){
212				DEBUGF(DLPQ1)("Job_status: forcing status '%s'", s);
213				if( safestrcasecmp(s,"s") == 0 ){
214					displayformat = REQ_DSHORT;
215				} else if( safestrcasecmp(s,"l") == 0 ){
216					displayformat = REQ_DLONG;
217				}
218				status_lines = Short_status_length_DYN;
219				break;
220			}
221		}
222		Free_line_list(&l);
223		Free_line_list(&listv);
224	}
225
226	/*
227	 * check for short status to be returned
228	 */
229
230	if( Return_short_status_DYN && displayformat == REQ_DLONG ){
231		Free_line_list(&l);
232		Split(&l,Return_short_status_DYN,File_sep,0,0,0,0,0,0);
233		if( Match_ipaddr_value( &l, &RemoteHost_IP ) == 0 ){
234			status_lines = Short_status_length_DYN;
235			DEBUGF(DLPQ1)("Job_status: truncating status to %d",
236				status_lines);
237		}
238		Free_line_list(&l);
239	}
240
241	DEBUGF(DLPQ1)("Job_status: doing '%s'", input );
242	Free_line_list(&l);
243	Split(&l,input,Whitespace,0,0,0,0,0,0);
244	if( l.count == 0 ){
245		SNPRINTF( error, sizeof(error)) "zero length command line");
246		goto error;
247	}
248
249	/* save l.list[0] */
250	name = l.list[0];
251
252	if( (s = Is_clean_name( name )) ){
253		SNPRINTF( error, sizeof(error))
254			_("printer '%s' has illegal character at '%s' in name"), name, s );
255		goto error;
256	}
257
258	Set_DYN(&Printer_DYN,name);
259	setproctitle( "lpd %s '%s'", Name, name );
260	SNPRINTF(buffer,sizeof(buffer))"%d",displayformat);
261	l.list[0] = buffer;
262
263	/* we have the hash key */
264	hash_key = Join_line_list_with_sep(&l,"_");
265	for( s = hash_key; (s = strpbrk(s,Whitespace)); ) *s = '_';
266
267	DEBUGF(DLPQ1)("Job_status: arg '%s'", s );
268	/* now we put back the l.list[0] value */
269
270	l.list[0] = name;
271	/* free the values l.list[0] */
272	Remove_line_list( &l, 0 );
273	name = Printer_DYN;
274
275	if( l.count && (s = l.list[0]) && s[0] == '-' ){
276		DEBUGF(DLPQ1)("Job_status: arg '%s'", s );
277		Free_line_list(&listv);
278		Split(&listv,s+1,Arg_sep,1,Value_sep,1,1,0,0);
279		Remove_line_list( &l, 0 );
280#ifdef ORIGINAL_DEBUG//JY@1020
281		DEBUGFC(DLPQ1)Dump_line_list( "Job_status: args", &listv );
282#endif
283		if( (n = Find_flag_value(&listv,"lines",Value_sep)) ) status_lines = n;
284		DEBUGF(DLPQ1)("Job_status: status_lines '%d'", status_lines );
285		Free_line_list(&listv);
286	}
287	if( safestrcasecmp( name, ALL ) ){
288		DEBUGF(DLPQ1)("Job_status: checking printcap entry '%s'",  name );
289		Get_queue_status( &l, sock, displayformat, status_lines,
290			&done_list, Max_status_size_DYN, hash_key );
291	} else {
292		/* we work our way down the printcap list, checking for
293			ones that have a spool queue */
294		/* note that we have already tried to get the 'all' list */
295
296		Get_all_printcap_entries();
297		for( i = 0; i < All_line_list.count; ++i ){
298			Set_DYN(&Printer_DYN, All_line_list.list[i] );
299			Debug = db;
300			DbgFlag = dbflag;
301			Get_queue_status( &l, sock, displayformat, status_lines,
302				&done_list, Max_status_size_DYN, hash_key );
303		}
304	}
305	Free_line_list( &l );
306	Free_line_list( &listv );
307	Free_line_list( &done_list );
308	DEBUGF(DLPQ3)("Job_status: DONE" );
309	return(0);
310
311 error:
312	DEBUGF(DLPQ2)("Job_status: error msg '%s'", error );
313	i = safestrlen(error);
314	if( (i = safestrlen(error)) >= (int)sizeof(error)-2 ){
315		i = sizeof(error) - 2;
316	}
317	error[i++] = '\n';
318	error[i] = 0;
319	Free_line_list( &l );
320	Free_line_list( &listv );
321	Free_line_list( &done_list );
322	if( Write_fd_str( *sock, error ) < 0 ) cleanup(0);
323	DEBUGF(DLPQ3)("Job_status: done" );
324#endif
325	return(0);
326}
327
328#ifdef REMOVE
329/***************************************************************************
330 * void Get_queue_status
331 * sock - used to send information
332 * displayformat - REQ_DSHORT, REQ_DLONG, REQ_VERBOSE
333 * tokens - arguments
334 *  - get the printcap entry (if any)
335 *  - check the control file for current status
336 *  - find and report the spool queue entries
337 ***************************************************************************/
338void Get_queue_status( struct line_list *tokens, int *sock,
339	int displayformat, int status_lines, struct line_list *done_list,
340	int max_size, char *hash_key )
341{
342	char msg[SMALLBUFFER], buffer[SMALLBUFFER], error[SMALLBUFFER],
343		number[LINEBUFFER], header[LARGEBUFFER];
344	char sizestr[SIZEW+TIMEW+32];
345	char *pr, *s, *t, *path, *identifier,
346		*jobname, *joberror, *class, *priority, *d_identifier,
347		*job_time, *d_error, *d_dest, *openname, *hf_name, *filenames,
348		*tempfile = 0, *file = 0, *end_of_name;
349	struct line_list outbuf, info, lineinfo, cache, cache_info;
350	int status = 0, len, ix, nx, flag, count, held, move,
351		server_pid, unspooler_pid, fd, nodest,
352		printable, dcount, destinations = 0,
353		d_copies, d_copy_done, permission, jobnumber, db, dbflag,
354		matches, tempfd, savedfd, lockfd, delta, err, cache_index,
355		total_held, total_move, jerror, jdone;
356	double jobsize;
357	struct stat statb;
358	struct job job;
359	time_t modified = 0;
360	time_t timestamp = 0;
361	time_t now = time( (void *)0 );
362
363	cache_index = -1;
364
365#ifdef ORIGINAL_DEBUG//JY@1020
366	DEBUG1("Get_queue_status: sock fd %d, checking '%s'", *sock, Printer_DYN );
367	if(DEBUGL1)Dump_line_list( "Get_queue_status: done_list", done_list );
368#endif
369
370	/* set printer name and printcap variables */
371
372	Init_job(&job);
373	Init_line_list(&info);
374	Init_line_list(&lineinfo);
375	Init_line_list(&outbuf);
376	Init_line_list(&cache);
377	Init_line_list(&cache_info);
378	/* for caching */
379	tempfile = 0;
380	savedfd = tempfd = lockfd = -1;
381
382	Check_max(tokens,2);
383	tokens->list[tokens->count] = 0;
384	msg[0] = 0;
385	header[0] = 0;
386	error[0] = 0;
387	pr = s = 0;
388
389	safestrncpy(buffer,Printer_DYN);
390	status = Setup_printer( Printer_DYN, error, sizeof(error), 0);
391	if( status ){
392		if( error[0] == 0 ){
393			SNPRINTF(error,sizeof(error))"Nonexistent printer '%s'", Printer_DYN);
394		}
395		goto error;
396	}
397
398	db = Debug;
399	dbflag = DbgFlag;
400	s = Find_str_value(&Spool_control,DEBUG,Value_sep);
401	if( !s ) s = New_debug_DYN;
402	Parse_debug( s, 0 );
403	if( !(DLPQMASK & DbgFlag) ){
404		Debug = db;
405		DbgFlag = dbflag;
406	} else {
407		int odb, odbf;
408		odb = Debug;
409		odbf = DbgFlag;
410		Debug = db;
411		DbgFlag = dbflag;
412		if( Log_file_DYN ){
413			fd = Trim_status_file( -1, Log_file_DYN, Max_log_file_size_DYN,
414				Min_log_file_size_DYN );
415			if( fd > 0 && fd != 2 ){
416				dup2(fd,2);
417				close(fd);
418				close(fd);
419			}
420		}
421		Debug = odb;
422		DbgFlag = odbf;
423	}
424
425	DEBUGF(DLPQ3)("Get_queue_status: sock fd %d, Setup_printer status %d '%s'", *sock, status, error );
426	/* set up status */
427	if( Find_exists_value(done_list,Printer_DYN,Value_sep ) ){
428		return;
429	}
430	Add_line_list(done_list,Printer_DYN,Value_sep,1,1);
431
432	/* check for permissions */
433
434	Perm_check.service = 'Q';
435	Perm_check.printer = Printer_DYN;
436
437	permission = Perms_check( &Perm_line_list, &Perm_check, 0, 0 );
438	DEBUGF(DLPQ1)("Job_status: permission '%s'", perm_str(permission));
439	if( permission == P_REJECT ){
440		SNPRINTF( error, sizeof(error))
441			_("%s: no permission to show status"), Printer_DYN );
442		goto error;
443	}
444
445	/* check to see if we have any cached information */
446	if( Lpq_status_cached_DYN > 0 && Lpq_status_file_DYN ){
447		fd = -1;
448		do{
449			DEBUGF(DLPQ1)("Job_status: getting lock on '%s'", Lpq_status_file_DYN);
450			lockfd = Checkwrite( Lpq_status_file_DYN, &statb, O_RDWR, 1, 0 );
451			if( lockfd < 0 ){
452				LOGERR_DIE(LOG_INFO)"Get_queue_status: cannot open '%s'",
453				Lpq_status_file_DYN);
454			}
455			if( Do_lock(lockfd, 0) < 0 ){
456				DEBUGF(DLPQ1)("Get_queue_status: did not get lock");
457				Do_lock(lockfd, 1);
458				DEBUGF(DLPQ1)("Get_queue_status: lock released");
459				close(lockfd); lockfd = -1;
460			}
461		}while( lockfd < 0 );
462		DEBUGF(DLPQ1)("Get_queue_status: lock succeeded");
463		Free_line_list(&cache);
464		Get_fd_image_and_split(lockfd, 0,0,&cache,Line_ends,0,0,0,0,0,0);
465#ifdef ORIGINAL_DEBUG//JY@1020
466		DEBUGFC(DLPQ3)Dump_line_list("Get_queue_status- cache", &cache );
467		DEBUGF(DLPQ3)("Get_queue_status: cache hash_key '%s'", hash_key );
468#endif
469		file = 0;
470		nx = -1;
471		if( cache.count < Lpq_status_cached_DYN ){
472			Check_max(&cache,Lpq_status_cached_DYN-cache.count);
473			for( ix = cache.count; ix < Lpq_status_cached_DYN; ++ix ){
474				cache.list[ix] = 0;
475			}
476			cache.count = ix;
477		}
478		for( ix = 0; file == 0 && ix < cache.count; ++ix ){
479			if( (s = cache.list[ix]) ){
480				if( (t = safestrchr(s,'=')) ){
481					*t = 0;
482					if( !strcmp(hash_key,s) ){
483						file = t+1;
484						cache_index = ix;
485					}
486					*t = '=';
487				}
488			}
489		}
490		/* if we have a file name AND it is not stale then we use it */
491		DEBUGF(DLPQ3)("Get_queue_status: found in cache '%s'", file );
492		fd = -1;
493		if( file ){
494			Split(&cache_info,file,Arg_sep,1,Value_sep,1,1,0,0);
495			file = Find_str_value(&cache_info,FILENAMES,Value_sep);
496		}
497#ifdef ORIGINAL_DEBUG//JY@1020
498		DEBUGFC(DLPQ3)Dump_line_list("Get_queue_status: cache_info", &cache_info );
499#endif
500		if( file && (fd = Checkread( file, &statb )) > 0 ){
501			modified = statb.st_mtime;
502			delta = now - modified;
503			if( Lpq_status_stale_DYN && delta > Lpq_status_stale_DYN ){
504				/* we cannot use it */
505				close(fd); fd = -1;
506			}
507		}
508		if( fd > 0 ){
509			modified = 0;
510			if( Queue_status_file_DYN && stat(Queue_status_file_DYN,&statb) == 0 ){
511				modified = statb.st_mtime;
512			}
513			timestamp = Find_flag_value(&cache_info,QUEUE_STATUS_FILE,Value_sep);
514			delta = modified - timestamp;
515			DEBUGF(DLPQ3)("Get_queue_status: queue status '%s', modified %lx, timestamp %lx, delta %d",
516				Queue_status_file_DYN, (long)(modified), (long)(timestamp), delta );
517			if( delta > Lpq_status_interval_DYN ){
518				/* we need to refresh the data */
519				close(fd); fd = -1;
520			}
521		}
522
523		if( fd > 0 ){
524			if( Status_file_DYN && stat(Status_file_DYN,&statb) == 0 ){
525				modified = statb.st_mtime;
526			}
527			timestamp = Find_flag_value(&cache_info,PRSTATUS,Value_sep);
528			delta = modified - timestamp;
529			DEBUGF(DLPQ3)("Get_queue_status: pr status '%s', modified %lx, timestamp %lx, delta %d",
530				Status_file_DYN, (long)(modified), (long)(timestamp), delta );
531			if( delta > Lpq_status_interval_DYN ){
532				/* we need to refresh the data */
533				close(fd); fd = -1;
534			}
535		}
536
537		if( fd > 0 ){
538			DEBUGF(DLPQ3)("Get_queue_status: reading cached status from fd '%d'", fd );
539			/* We can read the status from the cached data */
540			while( (ix = read( fd, buffer, sizeof(buffer)-1 )) > 0 ){
541				if( write( *sock, buffer, ix ) < 0 ){
542					cleanup(0);
543				}
544			}
545			close(fd); fd = -1;
546			goto remote;
547		}
548		/* OK, we have to cache the status in a file */
549		tempfd = Make_temp_fd( &tempfile );
550		savedfd = *sock;
551		*sock = tempfd;
552	}
553
554	end_of_name = 0;
555	if( displayformat != REQ_DSHORT ){
556		SNPRINTF( header, sizeof(header)) "%s: ",
557			Server_queue_name_DYN?"Server Printer":"Printer" );
558	}
559	len = safestrlen(header);
560	SNPRINTF( header+len, sizeof(header)-len) "%s@%s",
561		Printer_DYN, Report_server_as_DYN?Report_server_as_DYN:ShortHost_FQDN );
562	if( safestrcasecmp( buffer, Printer_DYN ) ){
563		len = safestrlen(header);
564		SNPRINTF( header+len, sizeof(header)-len) _(" (originally %s)"), buffer );
565	}
566	end_of_name = header+safestrlen(header);
567
568	if( status ){
569		len = safestrlen( header );
570		if( displayformat == REQ_VERBOSE ){
571			safestrncat( header, _("\n Error: ") );
572			len = safestrlen( header );
573		}
574		if( error[0] ){
575			SNPRINTF( header+len, sizeof(header)-len)
576				_(" - %s"), error );
577		} else if( !Spool_dir_DYN ){
578			SNPRINTF( header+len, sizeof(header)-len)
579				_(" - printer %s@%s not in printcap"), Printer_DYN,
580					Report_server_as_DYN?Report_server_as_DYN:ShortHost_FQDN );
581		} else {
582			SNPRINTF( header+len, sizeof(header)-len)
583				_(" - printer %s@%s has bad printcap entry"), Printer_DYN,
584					Report_server_as_DYN?Report_server_as_DYN:ShortHost_FQDN );
585		}
586		safestrncat( header, "\n" );
587		DEBUGF(DLPQ3)("Get_queue_status: forward header '%s'", header );
588		if( Write_fd_str( *sock, header ) < 0 ) cleanup(0);
589		header[0] = 0;
590		goto done;
591	}
592	if( displayformat == REQ_VERBOSE ){
593		safestrncat( header, "\n" );
594		if( Write_fd_str( *sock, header ) < 0 ) cleanup(0);
595		header[0] = 0;
596	}
597
598	/* get the spool entries */
599	Free_line_list( &outbuf );
600	Scan_queue( &Spool_control, &Sort_order, &printable,&held,&move,0,0,0,0,0 );
601	/* check for done jobs, remove any if there are some */
602	if( Remove_done_jobs() ){
603		Scan_queue( &Spool_control, &Sort_order, &printable,&held,&move,0,0,0,0,0 );
604	}
605
606#ifdef ORIGINAL_DEBUG//JY@1020
607	DEBUGF(DLPQ3)("Get_queue_status: total files %d", Sort_order.count );
608	DEBUGFC(DLPQ3)Dump_line_list("Get_queue_status- Sort_order", &Sort_order );
609#endif
610
611
612	/* set up the short format for folks */
613
614	if( displayformat == REQ_DLONG && Sort_order.count > 0 ){
615		/*
616		 Rank  Owner/ID  Class Job Files   Size Time
617		*/
618		Add_line_list(&outbuf,
619" Rank   Owner/ID                  Class Job Files                 Size Time"
620		,0,0,0);
621	}
622	error[0] = 0;
623
624	matches = 0;
625	total_held = 0;
626	total_move = 0;
627	for( count = 0; count < Sort_order.count; ++count ){
628		int printable, held, move;
629		printable = held = move = 0;
630		Free_job(&job);
631		Get_hold_file(&job, Sort_order.list[count] );
632		Job_printable(&job,&Spool_control, &printable,&held,&move,&jerror,&jdone);
633		DEBUGF(DLPQ3)("Get_queue_status: printable %d, held %d, move %d, error %d, done %d",
634			printable, held, move, jerror, jdone );
635#ifdef ORIGINAL_DEBUG//JY@1020
636		DEBUGFC(DLPQ4)Dump_job("Get_queue_status - info", &job );
637#endif
638		if( job.info.count == 0 ) continue;
639
640		if( tokens->count && Patselect( tokens, &job.info, 0) ){
641			continue;
642		}
643
644		number[0] = 0;
645		error[0] = 0;
646		msg[0] = 0;
647		nodest = 0;
648		s = Find_str_value(&job.info,PRSTATUS,Value_sep);
649		if( s == 0 ){
650			SNPRINTF(number,sizeof(number))"%d",count+1);
651		} else {
652			SNPRINTF(number,sizeof(number))"%s",s);
653		}
654		identifier = Find_str_value(&job.info,IDENTIFIER,Value_sep);
655		if( identifier == 0 ){
656			identifier = Find_str_value(&job.info,LOGNAME,Value_sep);
657		}
658		if( identifier == 0 ){
659			identifier = "???";
660		}
661		priority = Find_str_value(&job.info,PRIORITY,Value_sep);
662		class = Find_str_value(&job.info,CLASS,Value_sep);
663		jobname = Find_str_value(&job.info,JOBNAME,Value_sep);
664		filenames = Find_str_value(&job.info,FILENAMES,Value_sep);
665		jobnumber = Find_decimal_value(&job.info,NUMBER,Value_sep);
666		joberror = Find_str_value(&job.info,ERROR,Value_sep);
667		jobsize = Find_double_value(&job.info,SIZE,Value_sep);
668		job_time = Find_str_value(&job.info,JOB_TIME,Value_sep );
669		destinations = Find_flag_value(&job.info,DESTINATIONS,Value_sep);
670
671		openname = Find_str_value(&job.info,OPENNAME,Value_sep);
672		if( !openname ){
673			openname = Find_str_value(&job.info,TRANSFERNAME,Value_sep);
674		}
675		if( !openname ){
676			DEBUGF(DLPQ4)("Get_queue_status: no openname or transfername");
677			continue;
678		}
679		hf_name = Find_str_value(&job.info,HF_NAME,Value_sep);
680		if( !hf_name ){
681			DEBUGF(DLPQ4)("Get_queue_status: no hf_name");
682			continue;
683		}
684
685		/* we report this jobs status */
686
687		DEBUGF(DLPQ3)("Get_queue_status: joberror '%s'", joberror );
688		DEBUGF(DLPQ3)("Get_queue_status: class '%s', priority '%s'",
689			class, priority );
690
691		if( (Class_in_status_DYN && class) || priority == 0 ){
692			priority = class;
693		}
694
695		if( displayformat == REQ_DLONG ){
696			SNPRINTF( msg, sizeof(msg))
697				"%-*s %-*s ", RANKW-1, number, OWNERW-1, identifier );
698			while( (len = safestrlen(msg)) > (RANKW+OWNERW)
699				&& isspace(cval(msg+len-1)) && isspace(cval(msg+len-2)) ){
700				msg[len-1] = 0;
701			}
702			SNPRINTF( buffer, sizeof(buffer)) "%-*s %*d ",
703				CLASSW-1,priority, JOBW-1,jobnumber);
704			DEBUGF(DLPQ3)("Get_queue_status: msg len %d '%s', buffer %d, '%s'",
705				safestrlen(msg),msg, safestrlen(buffer), buffer );
706			DEBUGF(DLPQ3)("Get_queue_status: RANKW %d, OWNERW %d, CLASSW %d, JOBW %d",
707				RANKW, OWNERW, CLASSW, JOBW );
708			s = buffer;
709			while( safestrlen(buffer) > CLASSW+JOBW && (s = safestrchr(s,' ')) ){
710				if( cval(s+1) == ' ' ){
711					memmove(s,s+1,safestrlen(s)+1);
712				} else {
713					++s;
714				}
715			}
716			s = msg+safestrlen(msg)-1;
717			while( safestrlen(msg) + safestrlen(buffer) > RANKW+OWNERW+CLASSW+JOBW ){
718				if( cval(s) == ' ' && cval(s-1) == ' ' ){
719					*s-- = 0;
720				} else {
721					break;
722				}
723			}
724			s = buffer;
725			while( safestrlen(msg) + safestrlen(buffer) > RANKW+OWNERW+CLASSW+JOBW
726				&& (s = safestrchr(s,' ')) ){
727				if( cval(s+1) == ' ' ){
728					memmove(s,s+1,safestrlen(s)+1);
729				} else {
730					++s;
731				}
732			}
733			len = safestrlen(msg);
734
735			SNPRINTF(msg+len, sizeof(msg)-len)"%s",buffer);
736			if( joberror ){
737				len = safestrlen(msg);
738					SNPRINTF(msg+len,sizeof(msg)-len)
739					"ERROR: %s", joberror );
740			} else {
741				DEBUGF(DLPQ3)("Get_queue_status: jobname '%s'", jobname );
742
743				len = safestrlen(msg);
744				SNPRINTF(msg+len,sizeof(msg)-len)"%-s",jobname?jobname:filenames);
745
746				DEBUGF(DLPQ3)("Get_queue_status: jobtime '%s'", job_time );
747				job_time = Time_str(1, Convert_to_time_t(job_time));
748				if( !Full_time_DYN && (s = safestrchr(job_time,'.')) ) *s = 0;
749
750				{
751					char jobb[32];
752					SNPRINTF(jobb,sizeof(jobb)) "%0.0f", jobsize );
753					SNPRINTF( sizestr, sizeof(sizestr)) "%*s %-s",
754						SIZEW-1,jobb, job_time );
755				}
756
757				len = Max_status_line_DYN;
758				if( len >= (int)sizeof(msg)) len = sizeof(msg)-1;
759				len = len-safestrlen(sizestr);
760				if( len > 0 ){
761					/* pad with spaces */
762					for( nx = safestrlen(msg); nx < len; ++nx ){
763						msg[nx] = ' ';
764					}
765					msg[nx] = 0;
766				}
767				/* remove spaces if necessary */
768				while( safestrlen(msg) + safestrlen(sizestr) > Max_status_line_DYN ){
769					if( isspace( cval(sizestr) ) ){
770						memmove(sizestr, sizestr+1, safestrlen(sizestr)+1);
771					} else {
772						s = msg+safestrlen(msg)-1;
773						if( isspace(cval(s)) && isspace(cval(s-1)) ){
774							s[0] = 0;
775						} else {
776							break;
777						}
778					}
779				}
780				if( safestrlen(msg) + safestrlen(sizestr) >= Max_status_line_DYN ){
781					len = Max_status_line_DYN - safestrlen(sizestr);
782					msg[len-1] = ' ';
783					msg[len] = 0;
784				}
785				strcpy( msg+safestrlen(msg), sizestr );
786			}
787
788			if( Max_status_line_DYN < (int)sizeof(msg) ) msg[Max_status_line_DYN] = 0;
789
790			DEBUGF(DLPQ3)("Get_queue_status: adding '%s'", msg );
791			Add_line_list(&outbuf,msg,0,0,0);
792			DEBUGF(DLPQ3)("Get_queue_status: destinations '%d'", destinations );
793			if( nodest == 0 && destinations ){
794				for( dcount = 0; dcount < destinations; ++dcount ){
795					if( Get_destination( &job, dcount ) ) continue;
796#ifdef ORIGINAL_DEBUG//JY@1020
797					DEBUGFC(DLPQ3)Dump_line_list("Get_queue_status: destination",
798						&job.destination);
799#endif
800					d_error =
801						Find_str_value(&job.destination,ERROR,Value_sep);
802					d_dest =
803						Find_str_value(&job.destination,DEST,Value_sep);
804					d_copies =
805						Find_flag_value(&job.destination,COPIES,Value_sep);
806					d_copy_done =
807						Find_flag_value(&job.destination,COPY_DONE,Value_sep);
808					d_identifier =
809						Find_str_value(&job.destination,IDENTIFIER,Value_sep);
810					s = Find_str_value(&job.destination, PRSTATUS,Value_sep);
811					if( !s ) s = "";
812					SNPRINTF(number, sizeof(number))" - %-8s", s );
813					SNPRINTF( msg, sizeof(msg))
814						"%-*s %-*s ", RANKW, number, OWNERW, d_identifier );
815					len = safestrlen(msg);
816					SNPRINTF(msg+len, sizeof(msg)-len) " ->%s", d_dest );
817					if( d_copies > 1 ){
818						len = safestrlen( msg );
819						SNPRINTF( msg+len, sizeof(msg)-len)
820							_(" <cpy %d/%d>"), d_copy_done, d_copies );
821					}
822					if( d_error ){
823						len = safestrlen(msg);
824						SNPRINTF( msg+len, sizeof(msg)-len) " ERROR: %s", d_error );
825					}
826					Add_line_list(&outbuf,msg,0,0,0);
827				}
828			}
829			DEBUGF(DLPQ3)("Get_queue_status: after dests" );
830		} else if( displayformat == REQ_VERBOSE ){
831			SNPRINTF( header, sizeof(header))
832				_(" Job: %s"), identifier );
833			SNPRINTF( msg, sizeof(msg)) _("%s status= %s"),
834				header, number );
835			Add_line_list(&outbuf,msg,0,0,0);
836			SNPRINTF( msg, sizeof(msg)) _("%s size= %0.0f"),
837				header, jobsize );
838			Add_line_list(&outbuf,msg,0,0,0);
839			SNPRINTF( msg, sizeof(msg)) _("%s time= %s"),
840				header, job_time );
841			Add_line_list(&outbuf,msg,0,0,0);
842			if( joberror ){
843				SNPRINTF( msg, sizeof(msg)) _("%s error= %s"),
844						header, joberror );
845				Add_line_list(&outbuf,msg,0,0,0);
846			}
847			SNPRINTF( msg, sizeof(msg)) _("%s CONTROL="), header );
848			Add_line_list(&outbuf,msg,0,0,0);
849			s = Get_file_image(openname,0);
850			Add_line_list(&outbuf,s,0,0,0);
851			if( s ) free(s); s = 0;
852
853			SNPRINTF( msg, sizeof(msg)) _("%s HOLDFILE="), header );
854			Add_line_list(&outbuf,msg,0,0,0);
855			s = Get_file_image(hf_name,0);
856			Add_line_list(&outbuf,s,0,0,0);
857			if( s ) free(s); s = 0;
858		} else if( displayformat == REQ_DSHORT ){
859			if( printable ){
860				++matches;
861			} else if( held ){
862				++total_held;
863			} else if( move ){
864				++total_move;
865			}
866		}
867	}
868	DEBUGF(DLPQ3)("Get_queue_status: matches %d", matches );
869	/* this gives a short 1 line format with minimum info */
870	if( displayformat == REQ_DSHORT ){
871		len = safestrlen( header );
872		SNPRINTF( header+len, sizeof(header)-len) _(" %d job%s"),
873			matches, (matches == 1)?"":"s" );
874		if( total_held ){
875			len = safestrlen( header );
876			SNPRINTF( header+len, sizeof(header)-len) _(" (%d held)"),
877				total_held );
878		}
879		if( total_move ){
880			len = safestrlen( header );
881			SNPRINTF( header+len, sizeof(header)-len) _(" (%d move)"),
882				total_move );
883		}
884	}
885	len = safestrlen( header );
886
887#ifdef ORIGINAL_DEBUG//JY@1020
888	DEBUGFC(DLPQ4)Dump_line_list("Get_queue_status: job status",&outbuf);
889
890	DEBUGF(DLPQ3)(
891		"Get_queue_status: RemoteHost_DYN '%s', RemotePrinter_DYN '%s', Lp '%s'",
892		RemoteHost_DYN, RemotePrinter_DYN, Lp_device_DYN );
893#endif
894
895	if( displayformat != REQ_DSHORT ){
896		s = 0;
897		if( (s = Comment_tag_DYN) == 0 ){
898			if( (nx = PC_alias_line_list.count) > 1 ){
899				s = PC_alias_line_list.list[nx-1];
900			}
901		}
902		if( s ){
903			s = Fix_str(s);
904			len = safestrlen( header );
905			if( displayformat == REQ_VERBOSE ){
906				SNPRINTF( header+len, sizeof(header)-len) _(" Comment: %s"), s );
907			} else {
908				SNPRINTF( header+len, sizeof(header)-len) " '%s'", s );
909			}
910			if(s) free(s); s = 0;
911		}
912	}
913
914	len = safestrlen( header );
915	if( displayformat == REQ_VERBOSE ){
916		SNPRINTF( header+len, sizeof(header)-len)
917			_("\n Printing: %s\n Aborted: %s\n Spooling: %s"),
918				Pr_disabled(&Spool_control)?"yes":"no",
919				Pr_aborted(&Spool_control)?"yes":"no",
920				Sp_disabled(&Spool_control)?"yes":"no");
921	} else if( displayformat == REQ_DLONG || displayformat == REQ_DSHORT ){
922		flag = 0;
923		if( Pr_disabled(&Spool_control) || Sp_disabled(&Spool_control) || Pr_aborted(&Spool_control) ){
924			SNPRINTF( header+len, sizeof(header)-len) " (" );
925			len = safestrlen( header );
926			if( Pr_disabled(&Spool_control) ){
927				SNPRINTF( header+len, sizeof(header)-len) "%s%s",
928					flag?", ":"", "printing disabled" );
929				flag = 1;
930				len = safestrlen( header );
931			}
932			if( Pr_aborted(&Spool_control) ){
933				SNPRINTF( header+len, sizeof(header)-len) "%s%s",
934					flag?", ":"", "printing aborted" );
935				flag = 1;
936				len = safestrlen( header );
937			}
938			if( Sp_disabled(&Spool_control) ){
939				SNPRINTF( header+len, sizeof(header)-len) "%s%s",
940					flag?", ":"", "spooling disabled" );
941				len = safestrlen( header );
942			}
943			SNPRINTF( header+len, sizeof(header)-len) ")" );
944			len = safestrlen( header );
945		}
946	}
947
948	/*
949	 * check to see if this is a server or subserver.  If it is
950	 * for subserver,  then you can forget starting it up unless started
951	 * by the server.
952	 */
953	if( (s = Server_names_DYN) || (s = Destinations_DYN) ){
954		Split( &info, s, File_sep, 0,0,0,0,0,0);
955		len = safestrlen( header );
956		if( displayformat == REQ_VERBOSE ){
957			if ( Server_names_DYN ) {
958				s = "Subservers";
959			} else {
960				s = "Destinations";
961			}
962			SNPRINTF( header+len, sizeof(header)-len)
963			_("\n %s: "), s );
964		} else {
965			if ( Server_names_DYN ) {
966				s = "subservers";
967			} else {
968				s = "destinations";
969			}
970			SNPRINTF( header+len, sizeof(header)-len)
971			_(" (%s"), s );
972		}
973		for( ix = 0; ix < info.count; ++ix ){
974			len = safestrlen( header );
975			SNPRINTF( header+len, sizeof(header)-len)
976			"%s%s", (ix > 0)?", ":" ", info.list[ix] );
977		}
978		Free_line_list( &info );
979		if( displayformat != REQ_VERBOSE ){
980			safestrncat( header, ") " );
981		}
982	} else if( (s = Frwarding(&Spool_control)) ){
983		len = safestrlen( header );
984		if( displayformat == REQ_VERBOSE ){
985			SNPRINTF( header+len, sizeof(header)-len)
986				_("\n Redirected_to: %s"), s );
987		} else {
988			SNPRINTF( header+len, sizeof(header)-len)
989				_(" (redirect %s)"), s );
990		}
991	} else if( RemoteHost_DYN && RemotePrinter_DYN ){
992		len = safestrlen( header );
993		s = Frwarding(&Spool_control);
994		if( displayformat == REQ_VERBOSE ){
995			SNPRINTF( header+len, sizeof(header)-len)
996				"\n Destination: %s@%s", RemotePrinter_DYN, RemoteHost_DYN );
997		} else {
998			SNPRINTF( header+len, sizeof(header)-len)
999			_(" (dest %s@%s)"), RemotePrinter_DYN, RemoteHost_DYN );
1000		}
1001	}
1002	if( Server_queue_name_DYN ){
1003		len = safestrlen( header );
1004		if( displayformat == REQ_VERBOSE ){
1005			SNPRINTF( header+len, sizeof(header)-len)
1006				_("\n Serving: %s"), Server_queue_name_DYN );
1007		} else {
1008			SNPRINTF( header+len, sizeof(header)-len)
1009				_(" (serving %s)"), Server_queue_name_DYN );
1010		}
1011	}
1012	if( (s = Clsses(&Spool_control)) ){
1013		len = safestrlen( header );
1014		if( displayformat == REQ_VERBOSE ){
1015			SNPRINTF( header+len, sizeof(header)-len)
1016				_("\n Classes: %s"), s );
1017		} else {
1018			SNPRINTF( header+len, sizeof(header)-len)
1019				_(" (classes %s)"), s );
1020		}
1021	}
1022	if( (Hld_all(&Spool_control)) ){
1023		len = safestrlen( header );
1024		if( displayformat == REQ_VERBOSE ){
1025			SNPRINTF( header+len, sizeof(header)-len)
1026				_("\n Hold_all: on") );
1027		} else {
1028			SNPRINTF( header+len, sizeof(header)-len)
1029				_(" (holdall)"));
1030		}
1031	}
1032	if( Auto_hold_DYN ){
1033		len = safestrlen( header );
1034		if( displayformat == REQ_VERBOSE ){
1035			SNPRINTF( header+len, sizeof(header)-len)
1036				_("\n Auto_hold: on") );
1037		} else {
1038			SNPRINTF( header+len, sizeof(header)-len)
1039				_(" (autohold)"));
1040		}
1041	}
1042
1043	if( (s = Find_str_value( &Spool_control,MSG,Value_sep )) ){
1044		len = safestrlen( header );
1045		if( displayformat == REQ_VERBOSE ){
1046			SNPRINTF( header+len, sizeof(header)-len)
1047				_("\n Message: %s"), s );
1048		} else {
1049			SNPRINTF( header+len, sizeof(header)-len)
1050				_(" (message: %s)"), s );
1051		}
1052	}
1053	safestrncat( header, "\n" );
1054	if( Write_fd_str( *sock, header ) < 0 ) cleanup(0);
1055	header[0] = 0;
1056
1057	if( displayformat == REQ_DSHORT ) goto remote;
1058
1059	/* now check to see if there is a server and unspooler process active */
1060	path = Make_pathname( Spool_dir_DYN, Queue_lock_file_DYN );
1061	server_pid = 0;
1062	if( (fd = Checkread( path, &statb ) ) >= 0 ){
1063		server_pid = Read_pid( fd, (char *)0, 0 );
1064		close( fd );
1065	}
1066	DEBUGF(DLPQ3)("Get_queue_status: checking server pid %d", server_pid );
1067	free(path);
1068	if( server_pid > 0 && kill( server_pid, 0 ) ){
1069		DEBUGF(DLPQ3)("Get_queue_status: server %d not active", server_pid );
1070		server_pid = 0;
1071	}
1072
1073	path = Make_pathname( Spool_dir_DYN, Queue_unspooler_file_DYN );
1074	unspooler_pid = 0;
1075	if( (fd = Checkread( path, &statb ) ) >= 0 ){
1076		unspooler_pid = Read_pid( fd, (char *)0, 0 );
1077		close( fd );
1078	}
1079	if(path) free(path); path=0;
1080	DEBUGF(DLPQ3)("Get_queue_status: checking unspooler pid %d", unspooler_pid );
1081	if( unspooler_pid > 0 && kill( unspooler_pid, 0 ) ){
1082		DEBUGF(DLPQ3)("Get_queue_status: unspooler %d not active", unspooler_pid );
1083		unspooler_pid = 0;
1084	}
1085
1086	if( printable == 0 ){
1087		safestrncpy( msg, _(" Queue: no printable jobs in queue\n") );
1088	} else {
1089		/* check to see if there are files and no spooler */
1090		SNPRINTF( msg, sizeof(msg)) _(" Queue: %d printable job%s\n"),
1091			printable, printable > 1 ? "s" : "" );
1092	}
1093	if( Write_fd_str( *sock, msg ) < 0 ) cleanup(0);
1094	if( held ){
1095		SNPRINTF( msg, sizeof(msg))
1096		_(" Holding: %d held jobs in queue\n"), held );
1097		if( Write_fd_str( *sock, msg ) < 0 ) cleanup(0);
1098	}
1099
1100	msg[0] = 0;
1101	if( count && server_pid == 0 ){
1102		safestrncpy(msg, _(" Server: no server active") );
1103	} else if( server_pid ){
1104		len = safestrlen(msg);
1105		SNPRINTF( msg+len, sizeof(msg)-len) _(" Server: pid %d active"),
1106			server_pid );
1107	}
1108	if( unspooler_pid ){
1109		if( msg[0] ){
1110			safestrncat( msg, (displayformat == REQ_VERBOSE )?", ":"\n");
1111		}
1112		len = safestrlen(msg);
1113		SNPRINTF( msg+len, sizeof(msg)-len) _(" Unspooler: pid %d active"),
1114			unspooler_pid );
1115	}
1116	if( msg[0] ){
1117		safestrncat( msg, "\n" );
1118	}
1119	if( msg[0] ){
1120		if( Write_fd_str( *sock, msg ) < 0 ) cleanup(0);
1121	}
1122	msg[0] = 0;
1123
1124	if( displayformat == REQ_VERBOSE ){
1125		SNPRINTF( msg, sizeof(msg)) _("%s SPOOLCONTROL=\n"), header );
1126		if( Write_fd_str( *sock, msg ) < 0 ) cleanup(0);
1127		msg[0] = 0;
1128		for( ix = 0; ix < Spool_control.count; ++ix ){
1129			s = safestrdup3("   ",Spool_control.list[ix],"\n",__FILE__,__LINE__);
1130			if( Write_fd_str( *sock, s ) < 0 ) cleanup(0);
1131			free(s);
1132		}
1133	}
1134
1135	/*
1136	 * get the last status of the spooler
1137	 */
1138	Print_status_info( sock, Queue_status_file_DYN,
1139		_(" Status: "), status_lines, max_size );
1140
1141	if( Status_file_DYN ){
1142		Print_status_info( sock, Status_file_DYN,
1143			_(" Filter_status: "), status_lines, max_size );
1144	}
1145
1146	s = Join_line_list(&outbuf,"\n");
1147	if( s ){
1148		if( Write_fd_str(*sock,s) < 0 ) cleanup(0);
1149		free(s);
1150	}
1151	Free_line_list(&outbuf);
1152
1153 remote:
1154	if( tempfd > 0 ){
1155		/* we send the generated status back to the user */
1156		*sock = savedfd;
1157		DEBUGF(DLPQ3)("Get_queue_status: reporting created status" );
1158		if( lseek( tempfd, 0, SEEK_SET ) == -1 ){
1159			LOGERR_DIE(LOG_INFO)"Get_queue_status: lseek of '%s' failed",
1160				tempfile );
1161		}
1162		while( (ix = read( tempfd, buffer, sizeof(buffer)-1 )) > 0 ){
1163			if( write( *sock, buffer, ix ) < 0 ){
1164				break;
1165			}
1166		}
1167		close(tempfd); tempfd = -1;
1168#ifdef ORIGINAL_DEBUG//JY@1020
1169		DEBUGFC(DLPQ3)Dump_line_list("Get_queue_status- cache", &cache );
1170		/* now we update the cached information */
1171		DEBUGF(DLPQ3)("Get_queue_status: hash_key '%s', cache_index %d",
1172			hash_key, cache_index );
1173#endif
1174		modified = 0;
1175		nx = -1;
1176		for( ix = 0; cache_index < 0 && ix < cache.count; ++ix ){
1177			s = cache.list[ix];
1178			DEBUGF(DLPQ3)("Get_queue_status: [%d] '%s'", ix, s );
1179			Free_line_list(&cache_info);
1180			if( s && (t = strchr(s,'=')) ){
1181				Split(&cache_info,t+1,Arg_sep,1,Value_sep,1,1,0,0);
1182				if( (file = Find_str_value(&cache_info,FILENAMES,Value_sep)) ){
1183					/* we need to get the age of the file */
1184					if( stat( file,&statb ) ){
1185						/* the file is not there */
1186						cache_index = ix;
1187					} else if( modified == 0 || statb.st_mtime < modified ){
1188						nx = ix;
1189						modified = statb.st_mtime;
1190					}
1191				} else {
1192					cache_index = ix;
1193				}
1194			} else {
1195				DEBUGF(DLPQ3)("Get_queue_status: end of list [%d]", ix );
1196				/* end of the list */
1197				cache_index = ix;
1198			}
1199		}
1200		DEBUGF(DLPQ3)("Get_queue_status: cache_index %d", cache_index );
1201		if( cache_index < 0 ) cache_index = nx;
1202		DEBUGF(DLPQ3)("Get_queue_status: using cache_index %d", cache_index );
1203		if( cache_index < 0 ){
1204			FATAL(LOG_INFO)"Get_queue_status: cache entry not found");
1205		}
1206		SNPRINTF(buffer,sizeof(buffer))"%s.%d", Lpq_status_file_DYN,cache_index);
1207
1208		Free_line_list(&cache_info);
1209		Set_str_value(&cache_info,FILENAMES,buffer);
1210
1211		modified = 0;
1212		if( Queue_status_file_DYN && stat(Queue_status_file_DYN,&statb) == 0 ){
1213			modified = statb.st_mtime;
1214		}
1215		Set_flag_value(&cache_info,QUEUE_STATUS_FILE,modified);
1216
1217		modified = 0;
1218		if( Status_file_DYN && stat(Status_file_DYN,&statb) == 0 ){
1219			modified = statb.st_mtime;
1220		}
1221		Set_flag_value(&cache_info,PRSTATUS,modified);
1222		s = Join_line_list(&cache_info,",");
1223
1224		/* now set up the new values */
1225		if( cache.list[cache_index] ) free( cache.list[cache_index]); cache.list[cache_index] = 0;
1226		cache.list[cache_index] = safestrdup3(hash_key,"=",s,__FILE__,__LINE__);
1227		if( s ) free(s); s = 0;
1228
1229#ifdef ORIGINAL_DEBUG//JY@1020
1230		DEBUGFC(DLPQ3)Dump_line_list("Get_queue_status- new cache", &cache );
1231#endif
1232		if( rename( tempfile, buffer ) ){
1233			err = errno;
1234			unlink( Lpq_status_file_DYN );
1235			errno = err;
1236			LOGERR_DIE(LOG_INFO)"Get_queue_status: rename of '%s' to '%s' failed",
1237				tempfile, buffer );
1238		}
1239		s = Join_line_list( &cache,"\n" );
1240		if( lseek( lockfd, 0, SEEK_SET) == -1 ){
1241			Errorcode = JABORT;
1242			LOGERR_DIE(LOG_INFO) "Get_queue_status: lseek failed write file '%s'", Lpq_status_file_DYN);
1243		}
1244		if( ftruncate( lockfd, 0 ) ){
1245			Errorcode = JABORT;
1246			LOGERR_DIE(LOG_INFO) "Get_queue_status: ftruncate failed file '%s'", Lpq_status_file_DYN);
1247		}
1248		if( Write_fd_str( lockfd, s ) < 0 ){
1249			unlink( Lpq_status_file_DYN );
1250			Errorcode = JABORT;
1251			LOGERR_DIE(LOG_INFO) "Get_queue_status: write failed file '%s'", Lpq_status_file_DYN);
1252		}
1253		if(s) free(s); s = 0;
1254		close(lockfd);
1255
1256#if 0
1257		tempfd = Make_temp_fd( &tempfile );
1258		if( Write_fd_str( tempfd, s ) < 0 ){
1259			err = errno;
1260			unlink( Lpq_status_file_DYN );
1261			LOGERR_DIE(LOG_INFO)"Get_queue_status: write to '%s' failed",
1262				tempfile );
1263			errno = err;
1264			cleanup(0);
1265		}
1266		close(tempfd); tempfd = -1;
1267		if(s) free(s); s = 0;
1268		if( rename( tempfile, Lpq_status_file_DYN ) ){
1269			err = errno;
1270			unlink( Lpq_status_file_DYN );
1271			errno = err;
1272			LOGERR_DIE(LOG_INFO)"Get_queue_status: rename of '%s' to '%s' failed",
1273				tempfile, Lpq_status_file_DYN );
1274		}
1275#endif
1276		Free_line_list(&cache_info);
1277		Free_line_list(&cache);
1278		close( lockfd ); lockfd = -1;
1279	}
1280	if( Server_names_DYN ){
1281		Free_line_list(&info);
1282		Split(&info, Server_names_DYN, File_sep, 0,0,0,0,0,0);
1283		for( ix = 0; ix < info.count; ++ix ){
1284			DEBUGF(DLPQ3)("Get_queue_status: getting subserver status '%s'",
1285				info.list[ix] );
1286			Set_DYN(&Printer_DYN,info.list[ix]);
1287			Get_local_or_remote_status( tokens, sock, displayformat,
1288				status_lines, done_list, max_size, hash_key );
1289			DEBUGF(DLPQ3)("Get_queue_status: finished subserver status '%s'",
1290				info.list[ix] );
1291		}
1292	} else if( Destinations_DYN ){
1293		Free_line_list(&info);
1294		Split(&info, Destinations_DYN, File_sep, 0,0,0,0,0,0);
1295		for( ix = 0; ix < info.count; ++ix ){
1296			DEBUGF(DLPQ3)("Get_queue_status: getting destination status '%s'",
1297				info.list[ix] );
1298			Set_DYN(&Printer_DYN,info.list[ix]);
1299			Get_local_or_remote_status( tokens, sock, displayformat,
1300				status_lines, done_list, max_size, hash_key );
1301			DEBUGF(DLPQ3)("Get_queue_status: finished destination status '%s'",
1302				info.list[ix] );
1303		}
1304	} else if( RemoteHost_DYN ){
1305		/* now we look at the remote host */
1306		if( Find_fqdn( &LookupHost_IP, RemoteHost_DYN )
1307			&& ( !Same_host(&LookupHost_IP,&Host_IP )
1308				|| !Same_host(&LookupHost_IP,&Localhost_IP )) ){
1309			DEBUGF(DLPQ1)("Get_queue_status: doing local");
1310			if( safestrcmp(RemotePrinter_DYN, Printer_DYN) ){
1311				Set_DYN(&Printer_DYN,RemotePrinter_DYN);
1312				Get_queue_status( tokens, sock, displayformat, status_lines,
1313					done_list, max_size, hash_key );
1314			} else {
1315				SNPRINTF(msg,sizeof(msg))"Error: loop in printcap- %s@%s -> %s@%s\n",
1316					Printer_DYN, FQDNHost_FQDN, RemotePrinter_DYN, RemoteHost_DYN );
1317				Write_fd_str(*sock, msg );
1318			}
1319		} else {
1320			DEBUGF(DLPQ1)("Get_queue_status: doing remote %s@%s",
1321				RemotePrinter_DYN, RemoteHost_DYN);
1322			if( Remote_support_DYN ) uppercase( Remote_support_DYN );
1323			if( safestrchr( Remote_support_DYN, 'Q' ) ){
1324#ifdef ORIGINAL_DEBUG//JY@1020
1325				fd = Send_request( 'Q', displayformat, tokens->list, Connect_timeout_DYN,
1326					Send_query_rw_timeout_DYN, *sock );
1327#endif
1328				if( fd >= 0 ){
1329					char *tempfile;
1330					/* shutdown( fd, 1 ); */
1331					tempfd = Make_temp_fd( &tempfile );
1332					while( (nx = read(fd,msg,sizeof(msg))) > 0 ){
1333						if( Write_fd_len(tempfd,msg,nx) < 0 ) cleanup(0);
1334					}
1335					close(fd); fd = -1;
1336					Print_different_last_status_lines( sock, tempfd, status_lines, 0 );
1337					close(tempfd); tempfd = -1;
1338					unlink( tempfile );
1339				}
1340			}
1341		}
1342	}
1343
1344	DEBUGF(DLPQ3)("Get_queue_status: finished '%s'", Printer_DYN );
1345	goto done;
1346
1347 error:
1348	SNPRINTF(header,sizeof(header))"Printer: %s@%s - ERROR: %s",
1349		Printer_DYN, Report_server_as_DYN?Report_server_as_DYN:ShortHost_FQDN, error );
1350	DEBUGF(DLPQ1)("Get_queue_status: error msg '%s'", header );
1351	if( Write_fd_str( *sock, header ) < 0 ) cleanup(0);
1352 done:
1353	if( savedfd > 0 ) *sock = savedfd;
1354	Free_line_list(&info);
1355	Free_line_list(&lineinfo);
1356	Free_line_list(&outbuf);
1357	Free_line_list(&cache);
1358	Free_line_list(&cache_info);
1359	return;
1360}
1361
1362void Print_status_info( int *sock, char *file,
1363	char *prefix, int status_lines, int max_size )
1364{
1365	char *image;
1366	static char *atmsg = " at ";
1367	struct line_list l;
1368	int start, i;
1369	Init_line_list(&l);
1370
1371	DEBUGF(DLPQ1)("Print_status_info: '%s', lines %d, size %d",
1372		file, status_lines, max_size );
1373	if( status_lines > 0 ){
1374		i = (status_lines * 100)/1024;
1375		if( i == 0 ) i = 1;
1376		image = Get_file_image(file, i);
1377		Split(&l,image,Line_ends,0,0,0,0,0,0);
1378		if( l.count < status_lines ){
1379			if( image ) free( image ); image = 0;
1380			image = Get_file_image(file, 0);
1381			Split(&l,image,Line_ends,0,0,0,0,0,0);
1382		}
1383	} else {
1384		image = Get_file_image(file, max_size);
1385		Split(&l,image,Line_ends,0,0,0,0,0,0);
1386	}
1387
1388	DEBUGF(DLPQ1)("Print_status_info: line count %d", l.count );
1389
1390	start = 0;
1391	if( status_lines ){
1392		start = l.count - status_lines;
1393		if( start < 0 ) start = 0;
1394	}
1395	for( i = start; i < l.count; ++i ){
1396		char *s, *t, *u;
1397		s = l.list[i];
1398		if( (t = strstr( s, " ## " )) ){
1399			*t = 0;
1400		}
1401		/* make the date format short */
1402		if( !Full_time_DYN ){
1403			for( u = s; (t = strstr(u,atmsg)); u = t+safestrlen(atmsg) );
1404			if( u != s && (t = strrchr( u, '-' )) ){
1405				memmove( u, t+1, safestrlen(t+1)+1 );
1406			}
1407		}
1408		if( prefix && Write_fd_str(*sock,prefix) < 0 ) cleanup(0);
1409		if( Write_fd_str(*sock,s) < 0 ) cleanup(0);
1410		if( Write_fd_str(*sock,"\n") < 0 ) cleanup(0);
1411	}
1412	Free_line_list(&l);
1413	if( image) free(image); image = 0;
1414}
1415
1416void Print_different_last_status_lines( int *sock, int fd,
1417	int status_lines, int max_size )
1418{
1419	char header[SMALLBUFFER];
1420	struct line_list l;
1421	int start, last_printed, i, j, same;
1422	char *s, *t;
1423
1424	Init_line_list(&l);
1425#ifdef ORIGINAL_DEBUG//JY@1020
1426	DEBUGF(DLPQ1)("Print_different_last_status_lines: status lines %d", status_lines );
1427#endif
1428	Get_fd_image_and_split(fd,max_size,0,&l,Line_ends,0,0,0,0,0,0);
1429#ifdef ORIGINAL_DEBUG//JY@1020
1430	DEBUGFC(DLPQ1)Dump_line_list( "Print_different_last_status_lines", &l );
1431#endif
1432
1433	header[0] = 0;
1434	last_printed = start = -1;
1435	if( status_lines > 0 ) for( i = 0; i < l.count; ++i ){
1436		s = l.list[i];
1437		/* find up to the first colon */
1438		if( (t = safestrchr(s,':')) ){
1439			*t = 0;
1440		}
1441		same = !safestrcmp( header, s );
1442		if( !same ){
1443			safestrncpy(header,s);
1444		}
1445		if( t ) *t = ':';
1446		if( !same ){
1447			/* we print from i-1-(status_lines-1) to i-1 */
1448			start = i-status_lines;
1449			if( start <= last_printed ) start = last_printed + 1;
1450			for( j = start; j < i; ++j ){
1451				if( Write_fd_str(*sock,l.list[j]) < 0 ) cleanup(0);
1452				if( Write_fd_str(*sock,"\n") < 0 ) cleanup(0);
1453			}
1454			last_printed = i-1;
1455			DEBUGF(DLPQ1)("Print_different_last_status_lines: start %d, last_printed %d",
1456				start, last_printed );
1457		}
1458	}
1459	if( status_lines > 0 ){
1460		start = l.count - status_lines;
1461	}
1462	if( start <= last_printed ) start = last_printed + 1;
1463	DEBUGF(DLPQ1)("Print_different_last_status_lines: done, start %d", start );
1464	for( i = start; i < l.count ; ++i ){
1465		if( Write_fd_str(*sock,l.list[i]) < 0 ) cleanup(0);
1466		if( Write_fd_str(*sock,"\n") < 0 ) cleanup(0);
1467	}
1468	Free_line_list(&l);
1469}
1470
1471
1472void Get_local_or_remote_status( struct line_list *tokens, int *sock,
1473	int displayformat, int status_lines, struct line_list *done_list,
1474	int max_size, char *hash_key )
1475{
1476	char msg[SMALLBUFFER];
1477	int fd, n, tempfd;
1478
1479	/* we have to see if the host is on this machine */
1480
1481	DEBUGF(DLPQ1)("Get_local_or_remote_status: %s", Printer_DYN );
1482	if( !safestrchr(Printer_DYN,'@') ){
1483		DEBUGF(DLPQ1)("Get_local_or_remote_status: doing local");
1484		Get_queue_status( tokens, sock, displayformat, status_lines,
1485			done_list, max_size, hash_key );
1486		return;
1487	}
1488	Fix_Rm_Rp_info(0,0);
1489	/* now we look at the remote host */
1490	if( Find_fqdn( &LookupHost_IP, RemoteHost_DYN )
1491		&& ( !Same_host(&LookupHost_IP,&Host_IP )
1492			|| !Same_host(&LookupHost_IP,&Localhost_IP )) ){
1493		DEBUGF(DLPQ1)("Get_local_or_remote_status: doing local");
1494		Get_queue_status( tokens, sock, displayformat, status_lines,
1495			done_list, max_size, hash_key );
1496		return;
1497	}
1498	uppercase( Remote_support_DYN );
1499	if( safestrchr( Remote_support_DYN, 'Q' ) ){
1500		DEBUGF(DLPQ1)("Get_local_or_remote_status: doing remote %s@%s",
1501			RemotePrinter_DYN, RemoteHost_DYN);
1502#ifdef ORIGINAL_DEBUG//JY@1020
1503		fd = Send_request( 'Q', displayformat, tokens->list, Connect_timeout_DYN,
1504			Send_query_rw_timeout_DYN, *sock );
1505#endif
1506		if( fd >= 0 ){
1507			/* shutdown( fd, 1 ); */
1508			tempfd = Make_temp_fd( 0 );
1509			while( (n = read(fd,msg,sizeof(msg))) > 0 ){
1510				if( Write_fd_len(tempfd,msg,n) < 0 ) cleanup(0);
1511			}
1512			close(fd); fd = -1;
1513			Print_different_last_status_lines( sock, tempfd, status_lines, 0 );
1514			close(tempfd);
1515		}
1516	}
1517}
1518#endif
1519