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: lpr.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $";
28
29
30#include "lp.h"
31#include "child.h"
32#include "errorcodes.h"
33#include "fileopen.h"
34#include "getopt.h"
35#include "getprinter.h"
36#include "getqueue.h"
37#include "gethostinfo.h"
38#include "initialize.h"
39#include "linksupport.h"
40#include "patchlevel.h"
41#include "printjob.h"
42#include "sendjob.h"
43#include "lpd_jobs.h"
44
45/**** ENDINCLUDE ****/
46
47#undef EXTERN
48#undef DEFINE
49#define EXTERN
50#define DEFINE(X) X
51#include "lpr.h"
52
53/**** ENDINCLUDE ****/
54
55/***************************************************************************
56 * main()
57 * - top level of LPR Lite.  This is a cannonical method of handling
58 *   input.  Note that we assume that the LPD daemon will handle all
59 *   of the dirty work associated with formatting, printing, etc.
60 *
61 * 1. get the debug level from command line arguments
62 * 2. set signal handlers for cleanup
63 * 3. get the Host computer Name and user Name
64 * 4. scan command line arguments
65 * 5. check command line arguments for consistency
66 * 6. if we are spooling from STDIN, copy stdin to a file.
67 * 7. if we have a list of files,  check each for access
68 * 8. create a control file
69 * 9. send control file to server
70 *
71 ****************************************************************************/
72
73int main(int argc, char *argv[], char *envp[])
74{
75	off_t job_size;
76	char *s, *t, buffer[SMALLBUFFER], *send_to_pr = 0;
77	struct job prjob;
78	struct line_list opts, newargs;
79	int attempt = 0;
80	int n;
81
82#ifndef NODEBUG
83	Debug = 0;
84#endif
85
86	/* set signal handlers */
87	Is_lpr = 1;
88	Init_line_list( &newargs );
89	Init_line_list( &opts );
90	memset(&prjob, 0, sizeof(prjob) );
91	(void) plp_signal (SIGHUP, cleanup_HUP);
92	(void) plp_signal (SIGINT, cleanup_INT);
93	(void) plp_signal (SIGQUIT, cleanup_QUIT);
94	(void) plp_signal (SIGTERM, cleanup_TERM);
95	(void) signal(SIGCHLD, SIG_DFL);
96	(void) signal(SIGPIPE, SIG_IGN);
97
98	/*
99	 * set up the defaults
100	 */
101	Errorcode = 1;
102	Initialize(argc, argv, envp, 'D' );
103	Setup_configuration();
104	Job_number = DbgTest;
105
106
107	/* scan the input arguments, setting up values */
108	Get_parms(argc, argv);      /* scan input args */
109	if( Auth_JOB && !getenv( "AUTH" ) ){
110		FPRINTF(STDERR,
111		_("authentication requested (-A option) and AUTH environment variable not set") );
112		usage();
113	}
114
115	/* Note: we may need the open connection to the remote printer
116		to get our IP address if it is not available */
117
118    if(DEBUGL3){
119		struct stat statb;
120		int i;
121        LOGDEBUG("lpr: after init open fd's");
122        for( i = 0; i < 20; ++i ){
123            if( fstat(i,&statb) == 0 ){
124                LOGDEBUG("  fd %d (0%o)", i, statb.st_mode&S_IFMT);
125            }
126        }
127    }
128
129 again:
130
131	Free_job(&prjob);
132	Get_printer();
133	Fix_Rm_Rp_info(0,0);
134
135	DEBUG1("lpr: Lpr_opts_DYN '%s', argc %d", Lpr_opts_DYN, argc );
136	if( Lpr_opts_DYN ){
137		int i, j;
138
139		Split_cmd_line( &opts, Lpr_opts_DYN );
140		Check_max( &newargs, argc+2+opts.count+2 );
141		i = j = 0;
142
143		newargs.list[newargs.count++] = argv[0];
144		for( j = 0; j < opts.count; ++j ){
145			newargs.list[newargs.count++] = opts.list[j];
146		}
147		for( j = 1; j < argc; ++j ){
148			newargs.list[newargs.count++] = argv[j];
149		}
150		newargs.list[newargs.count] = 0;
151		if(DEBUGL1)Dump_line_list("lpr - new options",&newargs );
152		Optind = 0;
153		Files.count = 0;
154		Getopt(0,0,0);
155		Get_parms(newargs.count, newargs.list);      /* scan input args */
156		newargs.count = 0;
157	}
158	job_size = Make_job(&prjob);
159
160    if(DEBUGL3){
161		struct stat statb;
162		int i;
163        LOGDEBUG("lpr: after Make_job open fd's");
164        for( i = 0; i < 20; ++i ){
165            if( fstat(i,&statb) == 0 ){
166                LOGDEBUG("  fd %d (0%o)", i, statb.st_mode&S_IFMT);
167            }
168        }
169    }
170
171	/*
172	 * Fix the rest of the control file
173	 */
174	if( job_size == 0 ){
175		Free_job(&prjob);
176		Errorcode = 1;
177		FATAL(LOG_INFO)_("nothing to print"));
178	}
179
180	if( Check_for_rg_group( Logname_DYN ) ){
181		Errorcode = 1;
182		FATAL(LOG_INFO)_("cannot use printer - not in privileged group\n") );
183	}
184
185	if( Remote_support_DYN ) uppercase( Remote_support_DYN );
186	if( safestrchr( Remote_support_DYN, 'R' ) == 0 ){
187		Errorcode = 1;
188		FATAL(LOG_INFO) _("no remote support for %s@%s"),
189			RemotePrinter_DYN,RemoteHost_DYN );
190	}
191
192	/* we check to see if we need to do control file filtering */
193	/* we do not do any translation of formats */
194	s = 0;
195
196	n = Find_flag_value( &prjob.info,DATAFILE_COUNT,Value_sep);
197	if( Max_datafiles_DYN > 0 && n > Max_datafiles_DYN ){
198		Errorcode = 1;
199		FATAL(LOG_INFO) _("%d data files and maximum allowed %d"),
200					n, Max_datafiles_DYN );
201	}
202
203	send_to_pr = 0;
204	if( Direct_JOB ){
205		/* check to see if we have a socket connection specified */
206		send_to_pr = Printer_JOB;
207	} else if( Direct_DYN ){
208		send_to_pr = Lp_device_DYN;
209	}
210	Force_localhost_DYN = 0;
211	if( send_to_pr ){
212		Force_localhost_DYN = 0;
213		Lpr_bounce_DYN = Lpr_bounce_JOB = 0;
214		send_to_pr = safestrdup(send_to_pr,__FILE__,__LINE__);
215		Expand_percent(&send_to_pr);
216	}
217
218	DEBUG1("lpr: send_to_pr '%s'", send_to_pr );
219
220	if( Lpr_bounce_DYN || Lpr_bounce_JOB ){
221		int tempfd;
222		struct stat statb;
223		char *tempfile, *old_lp_value;
224		struct line_list *lp;
225
226		if(DEBUGL2) Dump_job( "lpr - before filtering", &prjob );
227		tempfd = Make_temp_fd(&tempfile);
228
229		old_lp_value = safestrdup(Find_str_value( &PC_entry_line_list, "lp", Value_sep ),
230			__FILE__,__LINE__);
231		Set_str_value( &PC_entry_line_list, LP, tempfile );
232		/* Print_job( output_device, status_device, job, timeout, poll_for_status ) */
233		Print_job( tempfd, -1, &prjob, 0, 0, User_filter_JOB );
234		Set_str_value( &PC_entry_line_list, LP, old_lp_value );
235		if( old_lp_value ) free( old_lp_value ); old_lp_value = 0;
236
237		close(tempfd);
238		tempfd = Checkread( tempfile, &statb );
239		if( tempfd < 0 ){
240			Errorcode = JABORT;
241			FATAL(LOG_INFO) _("Cannot open file '%s', %s"), tempfile, Errormsg( errno ) );
242		}
243		close(tempfd);
244		DEBUG2("lpr: jobs size now %0.0f", (double)(statb.st_size));
245		job_size = statb.st_size;
246		Free_listof_line_list(&prjob.datafiles);
247		lp = malloc_or_die(sizeof(lp[0]),__FILE__,__LINE__);
248		memset(lp,0,sizeof(lp[0]));
249		Check_max(&prjob.datafiles,1);
250		prjob.datafiles.list[prjob.datafiles.count++] = (void *)lp;
251		Set_str_value(lp,OPENNAME,tempfile);
252		Set_str_value(lp,"N",_("(lpr_filter)"));
253		Set_flag_value(lp,COPIES,1);
254		Set_double_value(lp,SIZE,job_size);
255		Fix_bq_format( 'f', lp );
256		User_filter_JOB = 0;
257	}
258
259	if(DEBUGL1)Dump_job("lpr - before Fix_control",&prjob);
260	Fix_control( &prjob, Control_filter_DYN, 0 );
261	if(DEBUGL1)Dump_job("lpr - after Fix_control",&prjob);
262
263	if( send_to_pr &&
264		((!strchr(send_to_pr,'@') && strchr(send_to_pr,'%'))
265			|| (send_to_pr[0] == '/') || strchr(send_to_pr,'|')) ){
266		int fd, pid, status_fd, poll_for_status;
267		char *id;
268
269		SETSTATUS(&prjob)"destination '%s'", send_to_pr );
270		Errorcode = 0;
271		fd = pid = status_fd = poll_for_status = 0;
272		fd = Printer_open(send_to_pr, &status_fd, &prjob,
273			Lpr_send_try_DYN, Connect_interval_DYN, Max_connect_interval_DYN,
274			Connect_grace_DYN, Connect_timeout_DYN, &pid, &poll_for_status );
275
276		/* note: we NEVER return fd == 0 or horrible things have happened */
277		DEBUG1("lpr: fd %d", fd );
278		if( fd <= 0 ){
279			Errorcode = JFAIL;
280			goto exit;
281		}
282		id = Find_str_value(&prjob.info,IDENTIFIER,Value_sep);
283		SETSTATUS(&prjob)"transferring job '%s'", id );
284		/* Print_job( output_device, status_device, job, timeout, poll_for_status, filter ) */
285		Set_str_value( &PC_entry_line_list, LP, s );
286		Errorcode = Print_job( fd, status_fd, &prjob, Send_job_rw_timeout_DYN, poll_for_status, User_filter_JOB );
287		/* we close close device */
288		DEBUG1("lpr: shutting down fd %d", fd );
289
290		fd = Shutdown_or_close( fd );
291		DEBUG1("lpr: after shutdown fd %d, status_fd %d", fd, status_fd );
292		if( status_fd > 0 ){
293			/* we shut down this connection as well */
294			shutdown(status_fd,1);
295			/* we wait for eof on status_fd */
296			buffer[0] = 0;
297			Get_status_from_OF(&prjob,"LP",pid,
298				status_fd, buffer, sizeof(buffer)-1, Send_job_rw_timeout_DYN, 0, 0, 0 );
299		}
300		if( fd > 0 ) close( fd ); fd = -1;
301		if( status_fd > 0 ) close( status_fd ); status_fd = -1;
302		if( pid > 0 ){
303			SETSTATUS(&prjob)"waiting for printer filter to exit");
304			Errorcode = Wait_for_pid( pid, "LP", 0, Send_job_rw_timeout_DYN );
305		}
306		DEBUG1("lpr: status %s", Server_status(Errorcode) );
307	} else {
308		Errorcode = 0;
309		attempt = 1;
310		do {
311			if( Errorcode ){
312				if(DEBUGL1)Dump_job("lpr - after error",&prjob);
313				buffer[0] = 0;
314				SNPRINTF(buffer,sizeof(buffer))
315					_("Status Information, attempt %d:\n"), attempt);
316				if( Lpr_send_try_DYN ){
317					n = strlen(buffer)-2;
318					SNPRINTF(buffer+n,sizeof(buffer)-n)
319					_(" of %d:\n"), Lpr_send_try_DYN);
320				}
321				Write_fd_str(2,buffer);
322				s = Join_line_list(&Status_lines,"\n ");
323				if( (t = safestrrchr(s,' ')) ) *t = 0;
324				Write_fd_str(2,s);
325				if(s) free(s); s = 0;
326				Init_line_list( &Status_lines );
327				++attempt;
328				n = Connect_interval_DYN + Connect_grace_DYN;
329				if( n > 0 ){
330					buffer[0] = 0;
331					SNPRINTF(buffer,sizeof(buffer))
332						_("Waiting %d seconds before retry\n"), n);
333					Write_fd_str(2,buffer);
334					plp_sleep( n );
335				}
336				Errorcode = 0;
337			}
338			Errorcode = Send_job( &prjob, &prjob, Connect_timeout_DYN,
339				Connect_interval_DYN,
340				Max_connect_interval_DYN,
341				Send_job_rw_timeout_DYN, User_filter_JOB );
342		} while( Errorcode && (Lpr_send_try_DYN == 0 || attempt < Lpr_send_try_DYN) );
343	}
344
345  exit:
346	if( send_to_pr ) free(send_to_pr); send_to_pr = 0;
347	if( Errorcode ){
348		Errorcode = 1;
349		if(DEBUGL1)Dump_job("lpr - after error",&prjob);
350		buffer[0] = 0;
351		SNPRINTF(buffer,sizeof(buffer))
352			_("Status Information, attempt %d:\n"), attempt);
353		if( Lpr_send_try_DYN ){
354			n = strlen(buffer)-2;
355			SNPRINTF(buffer+n,sizeof(buffer)-n)
356			_(" of %d:\n"), Lpr_send_try_DYN);
357		}
358		s = Join_line_list(&Status_lines,"\n ");
359		if( (t = safestrrchr(s,' ')) ) *t = 0;
360		Write_fd_str(2,s);
361		if(s) free(s); s = 0;
362		cleanup(0);
363	}
364
365	if( LP_mode_JOB && !Silent_JOB ){
366		char *id;
367		int n;
368		char msg[SMALLBUFFER];
369		id = Find_str_value(&prjob.info,IDENTIFIER,Value_sep);
370		if( id ){
371			SNPRINTF(msg,sizeof(msg)-1)_("request id is %s\n"), id );
372		} else {
373			n = Find_decimal_value(&prjob.info,NUMBER,Value_sep);
374			SNPRINTF(msg,sizeof(msg)-1)_("request id is %d\n"), n );
375		}
376		Write_fd_str(1, msg );
377	}
378
379	/* the dreaded -r (remove files) option */
380	if( Removefiles_JOB && !Errorcode ){
381		int i;
382		/* eliminate any possible game playing */
383		To_user();
384		for( i = 0; i < Files.count; ++i ){
385			if( unlink( Files.list[i] ) == -1 ){
386				WARNMSG(_("Error unlinking '%s' - %s"),
387					Files.list[i], Errormsg( errno ) );
388
389			}
390		}
391	}
392
393	if( Job_number ){
394		SNPRINTF(buffer,sizeof(buffer))_("Done %d\n"), Job_number);
395		Write_fd_str(1,buffer);
396		++Job_number;
397		goto again;
398	}
399	Free_line_list( &newargs );
400	Free_line_list( &opts );
401	Free_job(&prjob);
402	Free_line_list(&Files);
403	cleanup(0);
404	return(0);
405}
406
407
408/***************************************************************************
409 * void Get_parms(int argc, char *argv[])
410 * 1. Scan the argument list and get the flags
411 * 2. Check for duplicate information
412 ***************************************************************************/
413
414 void usage(void);
415
416
417 char LPR_optstr[]    /* LPR options */
418 = "1:2:3:4:#:ABC:D:F:GJ:K:NP:QR:T:U:VX:YZ:bcdfghi:klm:nprstvw:" ;
419 char LPR_bsd_optstr[]    /* LPR options */
420 = "1:2:3:4:#:ABC:D:F:GJ:K:NP:QR:T:U:VX:YZ:bcdfghi:klmnprstvw:" ;
421 char LP_optstr[]    /* LP options */
422 = 	"ckmprswd:BD:f:GH:n:o:P:q:S:t:T:X:Yy:";
423
424void Get_parms(int argc, char *argv[] )
425{
426	int option, i;
427	char *name, *s;
428
429	Verbose = 0;
430	if( argv[0] && (name = safestrrchr( argv[0], '/' )) ) {
431		++name;
432	} else {
433		name = argv[0];
434	}
435	/* check to see if we simulate (poorly) the LP options */
436	if( name && safestrcmp( name, "lp" ) == 0 ){
437		LP_mode_JOB = 1;
438	}
439	DEBUG1("Get_parms: LP_mode %d", LP_mode_JOB );
440	if( LP_mode_JOB ){
441		while( (option = Getopt( argc, argv, LP_optstr)) != EOF ){
442		DEBUG1("Get_parms: option %c", option );
443		switch( option ){
444		case 'A':   Auth_JOB = 1; break;
445		case 'B':   Lpr_bounce_JOB = 1; break;
446		case 'c':	break;	/* use symbolic link */
447		case 'k':	Lpr_zero_file_JOB = 1; break;	/* send input with 0 length */
448		case 'm':	/* send mail */
449					Mailname_JOB = getenv( "USER" );
450					if( Mailname_JOB == 0 ){
451						DIEMSG( _("USER environment variable undefined") );
452					}
453					break;
454		case 'p':	break;	/* ignore notification */
455		case 'r':	break;	/* ignore this option */
456		case 's':	Verbose = 0; Silent_JOB = 1; break;	/* suppress messages flag */
457		case 'w':	break;	/* no writing of message */
458		case 'd':	Set_DYN(&Printer_DYN, Optarg); /* destination */
459					Printer_JOB = Optarg;
460					break;
461		case 'D': 	Parse_debug(Optarg,1);
462					break;
463		case 'f':	Classname_JOB = Optarg;
464					break;
465		case 'H':	/* special handling - ignore */
466					break;
467		case 'n':	Copies_JOB = atoi( Optarg );	/* copies */
468					if( Copies_JOB <= 0 ){
469						DIEMSG( _("-ncopies -number of copies must be greater than 0\n"));
470					}
471					break;
472		case 'o':	if( safestrcasecmp( Optarg, "nobanner" ) == 0
473						|| safestrcasecmp( Optarg,_("nobanner") ) == 0 ){
474						No_header_JOB = 1;
475					} else if( safestrncasecmp( Optarg, "width", 5 ) == 0
476						|| safestrncasecmp( Optarg,_("width"), 5 ) == 0 ){
477						s = safestrchr( Optarg, '=' );
478						if( s ){
479							Pwidth_JOB = atoi( s+1 );
480						}
481					} else {
482						/* pass as Zopts */
483						if( Zopts_JOB ){
484							s = Zopts_JOB;
485							Zopts_JOB = safestrdup3(s,",",Optarg,
486								__FILE__,__LINE__);
487							free(s);
488						} else {
489							Zopts_JOB = safestrdup(Optarg,
490								__FILE__,__LINE__);
491						}
492					}
493					break;
494		case 'P':	break;	/* ignore page lis */
495		case 'q':	Priority_JOB = 'Z' - atoi(Optarg);	/* get priority */
496					if(Priority_JOB < 'A' ) Priority_JOB = 'A';
497					if(Priority_JOB > 'Z' ) Priority_JOB = 'Z';
498					break;
499		/* pass these as Zopts */
500		case 'S':
501		case 'T':
502		case 'y':
503					/* pass as Zopts */
504					if( Zopts_JOB ){
505						s = Zopts_JOB;
506						Zopts_JOB = safestrdup3(s,",",Optarg,
507							__FILE__,__LINE__);
508						free(s);
509					} else {
510						Zopts_JOB = safestrdup(Optarg,
511							__FILE__,__LINE__);
512					}
513					break;
514		case 't':
515				Check_str_dup( option, &Jobname_JOB, Optarg, M_JOBNAME);
516				break;
517		case 'X':
518				Check_str_dup( option, &User_filter_JOB, Optarg, M_JOBNAME);
519				break;
520		case 'Y': Direct_JOB = 1; break;
521		default:
522			usage();
523		    break;
524		}
525		}
526	} else {
527		while( (option = Getopt (argc, argv, LPR_bsd_DYN?LPR_bsd_optstr:LPR_optstr )) != EOF ) {
528		DEBUG1("Get_parms: option %c", option );
529		switch( option ){
530		case 'A':   Auth_JOB = 1; break;
531		case 'B':   Lpr_bounce_JOB = 1; break;
532		case '1':
533		    Check_str_dup( option, &Font1_JOB, Optarg, M_FONT);
534			break;
535		case '2':
536		    Check_str_dup( option, &Font2_JOB, Optarg, M_FONT);
537			break;
538		case '3':
539		    Check_str_dup( option, &Font3_JOB, Optarg, M_FONT);
540			break;
541		case '4':
542		    Check_str_dup( option, &Font4_JOB, Optarg, M_FONT);
543			break;
544		case 'C':
545		    Check_str_dup( option, &Classname_JOB, Optarg,
546			   M_CLASSNAME);
547		    break;
548		case 'D': 	Parse_debug(Optarg,1);
549			break;
550		case 'F':
551		    if( safestrlen (Optarg) != 1 ){
552		        DIEMSG( _("bad -F format string '%s'\n"), Optarg);
553		    }
554		    if( Format_JOB ){
555		        DIEMSG( _("duplicate format specification -F%s\n"), Optarg);
556		    } else {
557		        Format_JOB = *Optarg;
558		    }
559		    break;
560		case 'J':
561		    Check_str_dup( option, &Jobname_JOB, Optarg, M_JOBNAME);
562		    break;
563		case 'K':
564		case '#':
565		    Check_int_dup( option, &Copies_JOB, Optarg, 0);
566			if( Copies_JOB <= 0 ){
567		        DIEMSG( _("-Kcopies -number of copies must be greater than 0\n"));
568			}
569		    break;
570		case 'N':
571			Check_for_nonprintable_DYN = 0;
572			break;
573		case 'P':
574		    Printer_JOB = Optarg;
575		    Set_DYN(&Printer_DYN,Optarg);
576		    break;
577		case 'Q':
578			Use_queuename_flag_DYN = 1;
579			break;
580		case 'R':
581		    Check_str_dup( option, &Accntname_JOB, Optarg, M_ACCNTNAME );
582		    break;
583		case 'T':
584		    Check_str_dup( option, &Prtitle_JOB, Optarg, M_PRTITLE);
585		    break;
586		case 'U': Check_str_dup( option, &Username_JOB, Optarg, M_BNRNAME );
587		    break;
588		case 'V':
589			++Verbose;
590		    break;
591		case 'X':
592				Check_str_dup( option, &User_filter_JOB, Optarg, M_JOBNAME);
593				break;
594		case 'Y': Direct_JOB = 1; break;
595		case 'o': /* same as Z */
596		case 'Z':
597			if( Zopts_JOB ){
598				s = Zopts_JOB;
599				Zopts_JOB = safestrdup3(s,",",Optarg,
600					__FILE__,__LINE__);
601				free(s);
602			} else {
603				Zopts_JOB = safestrdup(Optarg,
604					__FILE__,__LINE__);
605			}
606		    break;
607		case 'k':	Lpr_zero_file_JOB = 1; break;	/* send input with 0 length */
608		case 'l':
609		case 'b':
610		    Binary_JOB = 1;
611		    break;
612		case 'h':
613		    Check_dup( option, &No_header_JOB);
614		    break;
615		case 'i':
616		    Check_int_dup( option, &Indent_JOB, Optarg, 0);
617		    break;
618		case 'm':
619		    /*
620		     * -m Mailname
621		     */
622			if( LPR_bsd_DYN ){
623					Mailname_JOB = getenv( "USER" );
624					if( Mailname_JOB == 0 ){
625						DIEMSG( _("USER environment variable undefined") );
626					}
627					break;
628			}
629			if( Optarg[0] == '-' ){
630				DIEMSG( _("Missing mail name") );
631			} else {
632				Mailname_JOB = Optarg;
633			}
634		    break;
635		case 'c':
636		case 'd':
637		case 'f':
638		case 'g':
639		case 'n':
640		case 'p':
641		case 't':
642		case 'v':
643		    if( Format_JOB ){
644		        DIEMSG( _("duplicate format specification -%c\n"), option);
645		    } else {
646		        Format_JOB = option;
647		    }
648		    break;
649		case 'w':
650		    Check_int_dup( option, &Pwidth_JOB, Optarg, 0);
651		    break;
652
653		/* Throw a sop to the whiners - let them wipe themselves out... */
654		/* remove files */
655		case 'r':
656			Removefiles_JOB = 1;
657			break;
658		case 's':
659			/* symbolic link - quietly ignored */
660			break;
661		default:
662			usage();
663		    break;
664		}
665		}
666	}
667
668	/*
669	 * set up the Parms[] array
670	 */
671	for( i = Optind; i < argc; ++i ){
672		Add_line_list(&Files,argv[i],0,0,0);
673	}
674	if( Verbose ){
675		if( Verbose > 1 ){
676			 Printlist( Copyright, 1 );
677		} else {
678			Write_fd_str( 2, Version );
679			Write_fd_str( 2, "\n" );
680		}
681	}
682}
683
684
685 char *LPR_msg [] =
686{
687 N_("Usage: %s [-Pprinter[@host]] [-A] [-B] [-Cclass] [-Fformat] [-G] [-Jinfo]\n"),
688 N_("   [-(K|#)copies] [-Q] [-Raccountname]  [-Ttitle]  [-Uuser[@host]] [-V]\n"),
689 N_("   [-Zoptions] [-b] [-m mailaddr] [-h] [-i indent] [-l] [-w width ] [-r]\n"),
690 N_("   [-Ddebugopt ] [--] [ filenames ...  ]\n"),
691 N_(" -A          - use authentication specified by AUTH environment variable\n"),
692 N_(" -B          - filter files and reduce job to single file before sending\n"),
693 N_(" -C class    - job class\n"),
694 N_(" -D debugopt - debugging flags\n"),
695 N_(" -F format   - job format\n"),
696 N_("   -b,-l        - binary or literal format\n"),
697 N_("    c,d,f,g,l,m,p,t,v are also format options\n"),
698 N_(" -G          - filter individual job files before sending\n"),
699 N_(" -J info     - banner and job information\n"),
700 N_(" -K copies, -# copies   - number of copies\n"),
701 N_(" -P printer[@host] - printer on host\n"),
702 N_(" -Q          - put 'queuename' in control file\n"),
703 N_(" -Raccntname - accounting information\n"),
704 N_(" -T title    - title for 'pr' (-p) formatting\n"),
705 N_(" -U username - override user name (restricted)\n"),
706 N_(" -V          - Verbose information during spooling\n"),
707 N_(" -X path     - user specified filter for job files\n"),
708 N_(" -Y          - connect and send to TCP/IP port (direct mode)\n"),
709 N_(" -Z options  - options to pass to filter\n"),
710 N_(" -h          - no header or banner page\n"),
711 N_(" -i indent   - indentation\n"),
712 N_(" -k          - do not use tempfile when sending to server\n"),
713 N_(" -m mailaddr - mail final status to mailaddr\n"),
714 N_(" -r          - remove files after spooling\n"),
715 N_(" -w width    - width to use\n"),
716 N_(" --          - end of options, files follow\n"),
717 N_(" filename '-'  reads from STDIN\n"),
718 N_(" PRINTER, LPDEST, NPRINTER, NGPRINTER environment variables set default printer.\n"),
719 0 };
720
721 char *LP_msg [] = {
722 N_("Usage: %s [-A] [-B] [-c] [-G] [-m] [-p] [-s] [-w] [-d printer@[host]]\n"),
723 N_("  [-f form-name] [-H special-handling]\n"),
724 N_("  [-n number] [-o options] [-P page-list]\n"),
725 N_("  [-q priority-level] [-S character-set]\n"),
726 N_("  [-S print-wheel] [-t title]\n"),
727 N_("  [-T content-type [-r]] [-y mode-list]\n"),
728 N_("  [-Ddebugopt ] [ filenames ...  ]\n"),
729 N_(" lp simulator using LPRng,  functionality may differ slightly\n"),
730 N_(" -A          - use authentication specified by AUTH environment variable\n"),
731 N_(" -B          - filter files and reduce job to single file before sending\n"),
732 N_(" -c          - (make copy before printing - ignored)\n"),
733 N_(" -d printer[@host]  - printer on host\n"),
734 N_(" -D debugflags  - debugging flags\n"),
735 N_(" -f formname - first letter used as job format\n"),
736 N_(" -G          - filter individual job files before sending\n"),
737 N_(" -H handling - (passed as -Z handling)\n"),
738 N_(" -m          - mail sent to $USER on completion\n"),
739 N_(" -n copies   - number of copies\n"),
740 N_(" -o option     nobanner, width recognized\n"),
741 N_("               (others passed as -Z option)\n"),
742 N_(" -P pagelist - (print page list - ignored)\n"),
743 N_(" -p          - (notification on completion - ignored)\n"),
744 N_(" -q          - priority - 0 -> Z (highest), 25 -> A (lowest)\n"),
745 N_(" -s          - (suppress messages - ignored)\n"),
746 N_(" -S charset  - (passed as -Z charset)\n"),
747 N_(" -t title    - job title\n"),
748 N_(" -T content  - (passed as -Z content)\n"),
749 N_(" -w          - (write message on completion - ignored)\n"),
750 N_(" -X path     - user specified filter for job files\n"),
751 N_(" -Y          - connect and send to TCP/IP port (direct mode)\n"),
752 N_(" -y mode     - (passed as -Z mode)\n"),
753 N_(" --          - end of options, files follow\n"),
754 N_(" filename '-'  reads from STDIN\n"),
755 N_(" PRINTER, LPDEST, NGPRINTER, NPRINTER environment variables set default printer.\n"),
756	0 };
757
758void prmsg( char **msg )
759{
760	int i;
761	char *s;
762	for( i = 0; (s = msg[i]); ++i ){
763		if(i == 0 ){
764			FPRINTF( STDERR,_(s), Name );
765		} else {
766			FPRINTF( STDERR, "%s",_(s) );
767		}
768	}
769}
770
771void usage(void)
772{
773	if(LP_mode_JOB ){
774		prmsg( LP_msg );
775	} else {
776		prmsg( LPR_msg );
777	}
778	Parse_debug("=",-1);
779	FPRINTF( STDERR, "%s\n", Version );
780	exit(1);
781}
782
783
784/***************************************************************************
785 * Make_job Parms()
786 * 1. we determine the name of the printer - Printer_DYN variable
787 * 2. we determine the host name to be used - RemoteHost_DYN variable
788 * 3. check the user name for consistency:
789 * 	We have the user name from the environment
790 * 	We have the user name from the -U option
791 *     Allow override if we are root or some silly system (like DOS)
792 * 		that does not support multiple users
793 ***************************************************************************/
794
795
796 void get_job_number( struct job *job );
797 double Copy_STDIN( struct job *job );
798 double Check_files( struct job *job );
799
800/***************************************************************************
801 * Commentary:
802 * The struct control_file{}  data structure contains fields that point to
803 * complete lines in the control file, i.e.- 'Jjobname', 'Hhostname'
804 * We set up this information in a data structure.
805 * Note that this is specific to the LPR program
806 *
807 * Make_job()
808 * 1. Get the control file number and name information
809 * 2. scan the set of variables,  and determine how much space is needed.
810 * 3. scan the data files,  and determine how much space is needed
811 * 4. allocate the space.
812 * 5. Copy variables to the allocated space,  setting up pointers in the
813 *    control_file data structure.
814 **************************************************************************/
815
816int Make_job( struct job *job )
817{
818	char nstr[SMALLBUFFER];	/* information */
819	struct jobwords *keys;	/* keyword entry in the parameter list */
820	char *s, *name;		/* buffer where we allocate stuff */
821	void *p;
822	char *originate_hostname = 0;
823	int i, n;
824	double job_size = 0;
825
826	if( Auth_JOB ){
827		Set_DYN(&Auth_DYN, getenv("AUTH") );
828	}
829
830	if(DEBUGL4)Dump_line_list("Make_job - PC_entry",&PC_entry_line_list );
831	if(DEBUGL4)Dump_parms("Make_job",Pc_var_list);
832	if(DEBUGL4)Dump_line_list("Make_job - job at start",&job->info );
833
834	/* check for priority in range */
835	if( Priority_JOB == 0 && Classname_JOB
836		&& !Break_classname_priority_link_DYN ) Priority_JOB = cval(Classname_JOB);
837	if( Priority_JOB == 0 && Default_priority_DYN ) Priority_JOB = cval(Default_priority_DYN);
838	if( Priority_JOB == 0 ) Priority_JOB = 'A';
839	if( islower(Priority_JOB) ) Priority_JOB = toupper( Priority_JOB );
840	if( !isupper( Priority_JOB ) ){
841		DIEMSG(
842		_("Priority (first letter of Class) not 'A' (lowest) to 'Z' (highest)") );
843	}
844
845	SNPRINTF(nstr,sizeof(nstr))"%c",Priority_JOB);
846	Set_str_value(&job->info,PRIORITY,nstr);
847
848	/* fix up the Classname_JOB 'C' option */
849
850	if( Classname_JOB == 0 ){
851		if( Backwards_compatible_DYN ){
852			Classname_JOB = ShortHost_FQDN;
853		} else {
854			SNPRINTF(nstr,sizeof(nstr))"%c",Priority_JOB);
855			Classname_JOB = nstr;
856		}
857	}
858	Set_str_value(&job->info,CLASS,Classname_JOB);
859
860	if( Files.count == 1 && !safestrcmp("-", Files.list[0]) ){
861		Files.count = 0;
862	}
863	/* fix up the jobname */
864	if( Jobname_JOB == 0 ){
865		if( Files.count == 0 ){
866			Set_str_value(&job->info,JOBNAME,_("(STDIN)") );
867		} else {
868			name = 0;
869			for( i = 0; i < Files.count; ++i ){
870				s = Files.list[i];
871				if( safestrcmp(s, "-" ) == 0 ) s = _("(STDIN)");
872				name = safeextend3(name,name?",":"",s,__FILE__,__LINE__);
873			}
874			Set_str_value(&job->info,JOBNAME, name );
875			if( name ) free(name); name = 0;
876		}
877	} else {
878		Set_str_value(&job->info,JOBNAME,Jobname_JOB );
879	}
880	if(DEBUGL4)Dump_line_list("Make_job - after jobname",&job->info);
881
882	/* fix up the banner name.
883	 * if you used the -U option,
884     *   check to see if you have root permissions
885	 *   set to -U value
886	 * else set to log name of user
887     * if No_header suppress banner
888	 */
889	if( Username_JOB ){
890		/* check to see if you were root */
891		if( 0 != OriginalRUID ){
892			struct line_list user_list;
893			char *str, *t;
894			struct passwd *pw;
895			int found;
896			uid_t uid;
897
898			DEBUG2("Make_job: checking '%s' for -U perms",
899				Allow_user_setting_DYN );
900			Init_line_list(&user_list);
901			Split( &user_list, Allow_user_setting_DYN,File_sep,0,0,0,0,0,0);
902
903			found = 0;
904			for( i = 0; !found && i < user_list.count; ++i ){
905				str = user_list.list[i];
906				DEBUG2("Make_job: checking '%s'", str );
907				uid = strtol( str, &t, 10 );
908				if( str == t || *t ){
909					/* try getpasswd */
910					pw = getpwnam( str );
911					if( pw ){
912						uid = pw->pw_uid;
913					}
914				}
915				DEBUG2( "Make_job: uid '%d'", uid );
916				found = ( uid == OriginalRUID );
917				DEBUG2( "Make_job: found '%d'", found );
918			}
919			if( !found ){
920				DEBUG1( _("-U (username) can only be used by ROOT") );
921				Username_JOB = 0;
922			}
923		}
924	}
925	if( Username_JOB ){
926		Clean_meta(Username_JOB);
927		if( (originate_hostname = strchr(Username_JOB,'@')) ){
928			*originate_hostname++ = 0;
929			for( s = originate_hostname; cval(s); ++s ){
930				if( isspace(cval(s)) ){
931					*s = '_';
932				}
933			}
934			if( (s = Find_fqdn( &LookupHost_IP, originate_hostname )) == 0 ){
935				Errorcode = JABORT;
936				FATAL(LOG_ERR) _("Get_local_host: '%s' FQDN name not found!"), originate_hostname );
937			} else {
938				originate_hostname = s;
939			}
940		}
941		Set_DYN(&Logname_DYN, Username_JOB );
942	}
943	if( !originate_hostname ) originate_hostname = FQDNHost_FQDN;
944	Bnrname_JOB = Logname_DYN;
945	if( No_header_JOB || Suppress_header_DYN ){
946		Bnrname_JOB = 0;
947	}
948	Set_str_value(&job->info,BNRNAME, Bnrname_JOB );
949
950	/* check the format */
951
952	DEBUG1("Make_job: before checking format '%c'", Format_JOB );
953	if( Binary_JOB ){
954		Format_JOB = 'l';
955	}
956	if( Format_JOB == 0 && Default_format_DYN ) Format_JOB = *Default_format_DYN;
957	if( Format_JOB == 0 ) Format_JOB = 'f';
958	if( isupper(Format_JOB) ) Format_JOB = tolower(Format_JOB);
959
960	DEBUG1("Make_job: after checking format '%c'", Format_JOB );
961	if( safestrchr( "aios", Format_JOB )
962		|| (Formats_allowed_DYN && !safestrchr( Formats_allowed_DYN, Format_JOB ) )){
963		DIEMSG( _("Bad format specification '%c'"), Format_JOB );
964	}
965
966	SNPRINTF(nstr,sizeof(nstr))"%c",Format_JOB);
967	Set_str_value(&job->info,FORMAT,nstr);
968	/* check to see how many files you want to print- limit of 52 */
969	if( Max_datafiles_DYN > 0 && Files.count > Max_datafiles_DYN ){
970		DIEMSG( _("Sorry, can only print %d files at a time, split job up"), Max_datafiles_DYN);
971	}
972	if( Copies_JOB == 0 ){
973		Copies_JOB = 1;
974	}
975	if( Max_copies_DYN && Copies_JOB > Max_copies_DYN ){
976		DIEMSG( _("Maximum of %d copies allowed"), Max_copies_DYN );
977	}
978	Set_flag_value(&job->info,COPIES,Copies_JOB);
979
980	/* check the for the -Q flag */
981	DEBUG1("Make_job: 'qq' flag %d, queue '%s', force_queuename '%s'",
982		Use_queuename_flag_DYN, Queue_name_DYN, Force_queuename_DYN );
983	if( Use_queuename_flag_DYN ){
984		Set_str_value(&job->info,QUEUENAME,Queue_name_DYN);
985	}
986	if( Force_queuename_DYN ){
987		Set_str_value(&job->info,QUEUENAME,Force_queuename_DYN);
988	}
989
990	get_job_number(job);
991
992	Set_str_value(&job->info,FROMHOST,originate_hostname);
993	if( isdigit(cval(originate_hostname)) ){
994		s = safestrdup2("ADDR",originate_hostname,__FILE__,__LINE__);
995		Set_str_value(&job->info,FILE_HOSTNAME,s);
996		if( s ) free(s); s = 0;
997	} else {
998		Set_str_value(&job->info,FILE_HOSTNAME,originate_hostname);
999	}
1000
1001	/* we put the option strings in the buffer */
1002	for( keys = Lpr_parms; keys->key; ++keys ){
1003		DEBUG2("Make_job: key '%s', maxlen %d, use '%s'",
1004			keys->keyword?*keys->keyword:0,keys->maxlen,keys->key);
1005		s = 0;
1006		/* see if we already have a value for this parameter.  If not,
1007			then we set it
1008		*/
1009		if( keys->keyword ){
1010			s = Find_str_value(&job->info,*keys->keyword,Value_sep);
1011		}
1012		p = keys->variable;
1013		nstr[0] = 0;
1014		n = 0;
1015		switch( keys->type ){
1016		case INTEGER_K:
1017			if( s ){
1018				n = strtol(s,0,0);
1019			} else if( p ){
1020				n = *(int *)p;
1021			}
1022			if( n ) Set_decimal_value(&job->info,keys->key,n);
1023			break;
1024		case STRING_K:
1025			if( s == 0 && p ) s = *(char **)p;
1026			if( s ) Set_str_value(&job->info,keys->key,s);
1027			break;
1028		default: break;
1029		}
1030	}
1031	if(DEBUGL2)Dump_job("Make_job - job after", job );
1032
1033	/*
1034	 * copy from standard in?
1035	 */
1036
1037	/* now we check to see if we have zero length flag */
1038	if( Lpr_zero_file_JOB ){
1039		if( Auth_JOB || Auth_DYN ){
1040			DIEMSG( _("authentication conficts with -k option"));
1041		}
1042		if( Send_block_format_DYN ){
1043			DIEMSG( _("send_block_format configuration option conficts with -k option"));
1044		}
1045		if( Send_data_first_DYN ){
1046			DIEMSG( _("send_data_first configuration option conficts with -k option"));
1047		}
1048		if(Copies_JOB > 1 ){
1049			DIEMSG( _("multiple copies conficts with -k option"));
1050		}
1051		if(Files.count ){
1052			DIEMSG( _("files on command line conflicts with -k option"));
1053		}
1054	}
1055	if( Files.count == 0 ){
1056		if( Lpr_zero_file_JOB || Direct_JOB ){
1057			struct line_list *lp;
1058			lp = malloc_or_die(sizeof(lp[0]),__FILE__,__LINE__);
1059			memset(lp,0,sizeof(lp[0]));
1060			Check_max(&job->datafiles,1);
1061			job->datafiles.list[job->datafiles.count++] = (void *) lp;
1062			Set_str_value(lp,"N","(STDIN)");
1063			Set_flag_value(lp,COPIES,1);
1064			SNPRINTF(nstr,sizeof(nstr))"%c",Format_JOB);
1065			Set_str_value(lp,FORMAT,nstr);
1066			Set_double_value(lp,SIZE,0 );
1067			job_size = 1;	/* make checker happy */
1068		} else {
1069			job_size = Copy_STDIN( job );
1070			job_size *= Copies_JOB;
1071		}
1072	} else {
1073		/*
1074		 * check to see that the input files are printable
1075		 */
1076		job_size = Check_files( job );
1077		job_size *= Copies_JOB;
1078	}
1079
1080	if(DEBUGL2) Dump_job( "Make_job - final value", job );
1081	return( job_size );
1082}
1083
1084/**************************************************************************
1085 * int get_job_number();
1086 * - get an integer value for the job number
1087 **************************************************************************/
1088
1089void get_job_number( struct job *job )
1090{
1091	int number = Job_number;
1092	if( number == 0 ) number = getpid();
1093	Fix_job_number( job, number );
1094}
1095
1096 struct jobwords Lpr_parms[]
1097 = {
1098{ 0,  STRING_K , &Accntname_JOB, M_ACCNTNAME, "R" },
1099{ &BNRNAME,  STRING_K , &Bnrname_JOB, M_BNRNAME, "L" },
1100{ &CLASS,  STRING_K , &Classname_JOB, M_CLASSNAME, "C" },
1101{ 0,  STRING_K , &Font1_JOB, M_FONT, "1" },
1102{ 0,  STRING_K , &Font2_JOB, M_FONT, "2" },
1103{ 0,  STRING_K , &Font3_JOB, M_FONT, "3" },
1104{ 0,  STRING_K , &Font4_JOB, M_FONT, "4" },
1105{ &FROMHOST,  STRING_K , &FQDNHost_FQDN, M_FROMHOST, "H" },
1106{ 0,  INTEGER_K , &Indent_JOB, M_INDENT, "I" },
1107{ &JOBNAME,  STRING_K , &Jobname_JOB, M_JOBNAME, "J" },
1108{ &LOGNAME,  STRING_K , &Logname_DYN, M_BNRNAME, "P" },
1109{ 0,  STRING_K , &Mailname_JOB, M_MAILNAME, "M" },
1110{ 0,  STRING_K , &Prtitle_JOB, M_PRTITLE, "T" },
1111{ 0,  INTEGER_K , &Pwidth_JOB, M_PWIDTH, "W" },
1112{ 0,  STRING_K , &Zopts_JOB, M_ZOPTS, "Z" },
1113{ 0,0,0,0,0 }
1114} ;
1115
1116
1117/***************************************************************************
1118 * off_t Copy_STDIN()
1119 * 1. we get the name of a temporary file
1120 * 2. we open the temporary file and read from STDIN until we get
1121 *    no more.
1122 * 3. stat the  temporary file to prevent games
1123 ***************************************************************************/
1124
1125double Copy_STDIN( struct job *job )
1126{
1127	int fd, count, printable = 1;
1128	double size = 0;
1129	char *tempfile;
1130	struct line_list *lp;
1131	struct stat statb;
1132	char buffer[LARGEBUFFER];
1133
1134	/* get a tempfile */
1135	if( Copies_JOB == 0 ) Copies_JOB = 1;
1136	fd = Make_temp_fd( &tempfile );
1137
1138	if( fd < 0 ){
1139		LOGERR_DIE(LOG_INFO) _("Make_temp_fd failed") );
1140	} else if( fd == 0 ){
1141		DIEMSG( _("You have closed STDIN! cannot pipe from a closed connection"));
1142	}
1143	DEBUG1("Temporary file '%s', fd %d", tempfile, fd );
1144	size = 0;
1145	while( (count = read( 0, buffer, sizeof(buffer))) > 0 ){
1146		if( write( fd, buffer, count ) < 0 ){
1147			Errorcode = JABORT;
1148			LOGERR_DIE(LOG_INFO) _("Copy_STDIN: write to temp file failed"));
1149		}
1150	}
1151	if( fstat( fd, &statb ) != 0 ){
1152		Errorcode = JABORT;
1153		LOGERR_DIE(LOG_INFO) _("Copy_STDIN: stat of temp fd '%d' failed"), fd);
1154	}
1155	printable = Check_lpr_printable( tempfile, fd, &statb, Format_JOB );
1156	if( printable ){
1157		size = statb.st_size;
1158		lp = malloc_or_die(sizeof(lp[0]),__FILE__,__LINE__);
1159		memset(lp,0,sizeof(lp[0]));
1160		Check_max(&job->datafiles,1);
1161		job->datafiles.list[job->datafiles.count++] = (void *) lp;
1162		Set_str_value(lp,"N","(STDIN)");
1163		Set_str_value(lp,OPENNAME,tempfile);
1164		Set_str_value(lp,TRANSFERNAME,tempfile);
1165		Set_flag_value(lp,COPIES,1);
1166		SNPRINTF(buffer,sizeof(buffer))"%c",Format_JOB);
1167		Set_str_value(lp,FORMAT,buffer);
1168		Set_double_value(lp,SIZE,size);
1169	} else {
1170		size = 0;
1171	}
1172	close(fd);
1173	return( size );
1174}
1175
1176/***************************************************************************
1177 * off_t Check_files( char **files, int filecount )
1178 * 2. check each of the input files for access
1179 * 3. stat the files and get the size
1180 * 4. Check for printability
1181 * 5. Put information in the data_file{} entry
1182 ***************************************************************************/
1183
1184double Check_files( struct job *job )
1185{
1186	double size = 0;
1187	int i, fd, printable = 1;
1188	struct stat statb;
1189	char *s, *tempfile;
1190	char buffer[SMALLBUFFER];
1191	struct line_list *lp;
1192
1193	for( i = 0; i < Files.count; ++i){
1194		tempfile = s = Files.list[i];
1195		DEBUG2( "Check_files: doing '%s'", s );
1196		if( safestrcmp( s, "-" ) == 0 ){
1197			size += Copy_STDIN( job );
1198			continue;
1199		}
1200		fd = Checkread( s, &statb );
1201		if( fd < 0 ){
1202			WARNMSG( _("Cannot open file '%s', %s"), s, Errormsg( errno ) );
1203			continue;
1204		}
1205		printable = 1;
1206		if( User_filter_JOB == 0 ){
1207			if( fstat( fd, &statb ) != 0 ){
1208				Errorcode = JABORT;
1209				LOGERR_DIE(LOG_INFO) _("Check_files: stat of temp fd '%d' failed"), fd);
1210			}
1211			printable = Check_lpr_printable( s, fd, &statb, Format_JOB );
1212		}
1213		close( fd );
1214		if( printable > 0 ){
1215			lp = malloc_or_die(sizeof(lp[0]),__FILE__,__LINE__);
1216			memset(lp,0,sizeof(lp[0]));
1217			Check_max(&job->datafiles,1);
1218			job->datafiles.list[job->datafiles.count++] = (void *) lp;
1219			Set_str_value(lp,OPENNAME,tempfile);
1220			Set_str_value(lp,TRANSFERNAME,s);
1221			Clean_meta(s);
1222			Set_str_value(lp,"N",s);
1223			Set_flag_value(lp,COPIES,1);
1224			SNPRINTF(buffer,sizeof(buffer))"%c",Format_JOB);
1225			Set_str_value(lp,FORMAT,buffer);
1226			size = size + statb.st_size;
1227			Set_double_value(lp,SIZE,(double)(statb.st_size) );
1228			DEBUG2( "Check_files: printing '%s'", s );
1229		} else {
1230			DEBUG2( "Check_files: not printing '%s'", s );
1231		}
1232	}
1233	if( Copies_JOB ) size *= Copies_JOB;
1234	DEBUG2( "Check_files: %d files, size %0.0f", job->datafiles.count, size );
1235	return( size );
1236}
1237
1238/***************************************************************************
1239 * int Check_lpr_printable(char *file, int fd, struct stat *statb, int format )
1240 * 1. Check to make sure it is a regular file.
1241 * 2. Check to make sure that it is not 'binary data' file
1242 * 3. If a text file,  check to see if it has some control characters
1243 *
1244 ***************************************************************************/
1245
1246int Check_lpr_printable(char *file, int fd, struct stat *statb, int format )
1247{
1248    char buf[LINEBUFFER];
1249    int n, i, c;                /* Acme Integers, Inc. */
1250    int printable = 0;
1251	char *err = _("cannot print '%s': %s");
1252
1253	if( Check_for_nonprintable_DYN == 0 ) return(1);
1254	/*
1255	 * Do an LSEEK on the file, i.e.- see to the start
1256	 * Ignore any error return
1257	 */
1258	lseek( fd, 0, SEEK_SET );
1259    if(!S_ISREG( statb->st_mode )) {
1260		DIEMSG(err, file,_("not a regular file"));
1261    } else if(statb->st_size == 0) {
1262		/* empty file */
1263		printable = -1;
1264    } else if ((n = read (fd, buf, sizeof(buf))) <= 0) {
1265        DIEMSG (err, file,_("cannot read it"));
1266    } else if (format != 'p' && format != 'f' ){
1267        printable = 1;
1268    } else if (is_exec ( buf, n)) {
1269        DIEMSG (err, file,_("executable program"));
1270    } else if (is_arch ( buf, n)) {
1271        DIEMSG (err, file,_("archive file"));
1272    } else {
1273        printable = 1;
1274		if( Min_printable_count_DYN && n > Min_printable_count_DYN ){
1275			n = Min_printable_count_DYN;
1276		}
1277		for (i = 0; printable && i < n; ++i) {
1278			c = cval(buf+i);
1279			/* we allow backspace, escape, ^D */
1280			if( !isprint( c ) && !isspace( c )
1281				&& c != 0x08 && c != 0x1B && c!= 0x04 ) printable = 0;
1282		}
1283		if( !printable ) DIEMSG (err, file,
1284			_("unprintable characters at start of file, check your LANG environment variable as well as the input file"));
1285    }
1286    return(printable);
1287}
1288
1289/***************************************************************************
1290 * The is_exec and is_arch are system dependent functions which
1291 * check if a file is an executable or archive file, based on the
1292 * information in the header.  Note that most of the time we will end
1293 * up with a non-printable character in the first 100 characters,  so
1294 * this test is moot.
1295 *
1296 * I swear I must have been out of my mind when I put these tests in.
1297 * In fact,  why bother with them?
1298 *
1299 * Patrick Powell Wed Apr 12 19:58:58 PDT 1995
1300 *   On review, I agree with myself. Sun Jan 31 06:36:28 PST 1999
1301 ***************************************************************************/
1302
1303#if defined(HAVE_A_OUT_H) && !defined(_AIX41)
1304#include <a.out.h>
1305#endif
1306
1307#ifdef HAVE_EXECHDR_H
1308#include <sys/exechdr.h>
1309#endif
1310
1311/* this causes trouble, eg. on SunOS. */
1312#ifdef IS_NEXT
1313#  ifdef HAVE_SYS_LOADER_H
1314#    include <sys/loader.h>
1315#  endif
1316#  ifdef HAVE_NLIST_H
1317#    include <nlist.h>
1318#  endif
1319#  ifdef HAVE_STAB_H
1320#    include <stab.h>
1321#  endif
1322#  ifdef HAVE_RELOC_H
1323#   include <reloc.h>
1324#  endif
1325#endif /* IS_NEXT */
1326
1327#if defined(HAVE_FILEHDR_H) && !defined(HAVE_A_OUT_H)
1328#include <filehdr.h>
1329#endif
1330
1331#if defined(HAVE_AOUTHDR_H) && !defined(HAVE_A_OUT_H)
1332#include <aouthdr.h>
1333#endif
1334
1335#ifdef HAVE_SGS_H
1336#include <sgs.h>
1337#endif
1338
1339/***************************************************************************
1340 * I really don't want to know.  This alone tempts me to rip the code out
1341 * Patrick Powell Wed Apr 12 19:58:58 PDT 1995
1342 ***************************************************************************/
1343#ifndef XYZZQ_
1344#define XYZZQ_ 1		/* ugh! antediluvian BSDism, I think */
1345#endif
1346
1347#ifndef N_BADMAG
1348#  ifdef NMAGIC
1349#    define N_BADMAG(x) \
1350	   ((x).a_magic!=OMAGIC && (x).a_magic!=NMAGIC && (x).a_magic!=ZMAGIC)
1351#  else				/* no NMAGIC */
1352#    ifdef MAG_OVERLAY		/* AIX */
1353#      define N_BADMAG(x) (x.a_magic == MAG_OVERLAY)
1354#    endif				/* MAG_OVERLAY */
1355#  endif				/* NMAGIC */
1356#endif				/* N_BADMAG */
1357
1358int is_exec( char *buf, int n)
1359{
1360    int i = 0;
1361
1362#ifdef N_BADMAG		/* BSD, non-mips Ultrix */
1363#  ifdef HAVE_STRUCT_EXEC
1364    if (n >= (int)sizeof (struct exec)){
1365		i |= !(N_BADMAG ((*(struct exec *) buf)));
1366	}
1367#  else
1368    if (n >= (int)sizeof (struct aouthdr)){
1369		i |= !(N_BADMAG ((*(struct aouthdr *) buf)));
1370	}
1371#  endif
1372#endif
1373
1374#ifdef ISCOFF		/* SVR4, mips Ultrix */
1375    if (n >= (int)sizeof (struct filehdr)){
1376		i |= (ISCOFF (((struct filehdr *) buf)->f_magic));
1377	}
1378#endif
1379
1380#ifdef MH_MAGIC		/* NeXT */
1381    if (n >= (int)sizeof (struct mach_header)){
1382		i |= (((struct mach_header *) buf)->magic == MH_MAGIC);
1383	}
1384#endif
1385
1386#ifdef IS_DATAGEN	/* Data General (forget it! ;) */
1387    {
1388		if( n > (int)sizeof (struct header)){
1389			i |= ISMAGIC (((struct header *)buff->magic_number));
1390		}
1391    }
1392#endif
1393
1394    return (i);
1395}
1396
1397#include <ar.h>
1398
1399int is_arch(char *buf, int n)
1400{
1401	int i = 0;
1402#ifdef ARMAG
1403	if( n >= SARMAG ){
1404		i = !memcmp( buf, ARMAG, SARMAG);
1405	}
1406#endif				/* ARMAG */
1407    return(i);
1408}
1409
1410void Dienoarg(int option)
1411{
1412	DIEMSG (_("option '%c' missing argument"), option);
1413}
1414
1415/***************************************************************************
1416 * Check_int_dup (int option, int *value, char *arg)
1417 * 1.  check to see if value has been set
1418 * 2.  if not, then get integer value from arg
1419 ***************************************************************************/
1420
1421void Check_int_dup (int option, int *value, char *arg, int maxvalue)
1422{
1423	char *convert;
1424
1425	if (arg == 0) {
1426		Dienoarg (option);
1427	}
1428	convert = arg;
1429	*value = strtol( arg, &convert, 10 );
1430	if( *value < 0 || convert == arg || *convert ){
1431		DIEMSG (_("option %c parameter `%s` is not positive integer value"),
1432		        option, arg );
1433	}
1434	if( maxvalue > 0 && *value > maxvalue ){
1435		DIEMSG (_("option %c parameter `%s` is not integer value from 0 - %d"),
1436		        option, arg, maxvalue );
1437	}
1438}
1439
1440/***************************************************************************
1441 * Check_str_dup(int option, char *value, char *arg)
1442 * 1.  check to see if value has been set
1443 * 2.  if not, then set it
1444 ***************************************************************************/
1445
1446void Check_str_dup(int option, char **value, char *arg, int maxlen )
1447{
1448	if (arg == 0) {
1449		Dienoarg (option);
1450	}
1451	*value = arg;
1452}
1453
1454/***************************************************************************
1455 * 1.  check to see if value has been set
1456 * 2.  if not, then set it
1457 ***************************************************************************/
1458
1459void Check_dup(int option, int *value)
1460{
1461	*value = 1;
1462}
1463