1/*
2 * $Id: main.c,v 1.31 2009-10-29 13:38:15 didg Exp $
3 *
4 * Copyright (c) 1990,1995 Regents of The University of Michigan.
5 * All Rights Reserved.  See COPYRIGHT.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include <config.h>
10#endif /* HAVE_CONFIG_H */
11
12#include <string.h>
13
14#include <sys/param.h>
15#include <sys/time.h>
16#include <sys/uio.h>
17#include <sys/file.h>
18#include <sys/socket.h>
19#include <atalk/logger.h>
20
21/* POSIX.1 sys/wait.h check */
22#include <sys/types.h>
23#ifdef HAVE_SYS_WAIT_H
24#include <sys/wait.h>
25#endif /* HAVE_SYS_WAIT_H */
26#ifndef WEXITSTATUS
27#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
28#endif /* ! WEXITSTATUS */
29#ifndef WIFEXITED
30#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
31#endif /* ! WIFEXITED */
32
33#include <errno.h>
34
35/* STDC check */
36#if STDC_HEADERS
37#include <string.h>
38#else /* STDC_HEADERS */
39#ifndef HAVE_STRCHR
40#define strchr index
41#define strrchr index
42#endif /* HAVE_STRCHR */
43char *strchr (), *strrchr ();
44#ifndef HAVE_MEMCPY
45#define memcpy(d,s,n) bcopy ((s), (d), (n))
46#define memmove(d,s,n) bcopy ((s), (d), (n))
47#endif /* ! HAVE_MEMCPY */
48#endif /* STDC_HEADERS */
49
50#include <signal.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <netdb.h>
54#include <fcntl.h>
55#ifdef HAVE_UNISTD_H
56#include <unistd.h>
57#endif /* HAVE_UNISTD_H */
58
59#include <netatalk/endian.h>
60#include <netatalk/at.h>
61#include <atalk/compat.h>
62#include <atalk/atp.h>
63#include <atalk/pap.h>
64#include <atalk/paths.h>
65#include <atalk/util.h>
66#include <atalk/nbp.h>
67#include <atalk/unicode.h>
68
69#include "printer.h"
70#include "printcap.h"
71#include "session.h"
72#include "uam_auth.h"
73#include "print_cups.h"
74
75
76#define PIPED_STATUS	"status: print spooler processing job"
77
78struct printer	defprinter;
79struct printer	*printers = NULL;
80
81int		debug = 0;
82static char	*conffile = _PATH_PAPDCONF;
83char		*printcap = _PATH_PAPDPRINTCAP;
84unsigned char	connid, quantum, sock, oquantum = PAP_MAXQUANTUM;
85char		*cannedstatus = PIPED_STATUS;
86struct printer	*printer = NULL;
87char		*version = VERSION;
88static char	*pidfile = _PATH_PAPDLOCK;
89
90char		*uamlist;
91char		*uampath = _PATH_PAPDUAMPATH;
92
93/* Prototypes for locally used functions */
94int getstatus( struct printer *pr, char *buf );
95int rprintcap( struct printer *pr );
96static void getprinters( char *cf );
97
98
99/* this only needs to be used by the server process */
100static void papd_exit(const int i)
101{
102  server_unlock(pidfile);
103  auth_unload();
104  exit(i);
105}
106
107static void
108die(int n)
109{
110    struct printer	*pr;
111    struct at_addr	addr;
112
113    memset(&addr, 0, sizeof(addr));
114
115    for ( pr = printers; pr; pr = pr->p_next ) {
116	if ( pr->p_flags & P_REGISTERED ) {
117	    if ( nbp_unrgstr( pr->p_name, pr->p_type, pr->p_zone, &addr ) < 0 ) {
118		LOG(log_error, logtype_papd, "can't unregister %s:%s@%s", pr->p_name,
119			pr->p_type, pr->p_zone );
120		papd_exit( n + 1 );
121	    }
122	    LOG(log_info, logtype_papd, "unregister %s:%s@%s", pr->p_name, pr->p_type,
123		    pr->p_zone );
124	}
125#ifdef HAVE_CUPS
126	if ( pr->p_flags & P_SPOOLED && pr->p_flags & P_CUPS_PPD ) {
127		LOG(log_info, logtype_papd, "Deleting CUPS temp PPD file for %s (%s)", pr->p_name, pr->p_ppdfile);
128		unlink (pr->p_ppdfile);
129	}
130#endif /* HAVE_CUPS */
131
132    }
133    papd_exit( n );
134}
135
136static void
137reap(int sig _U_)
138{
139    int		status;
140    int		pid;
141
142    while (( pid = wait3( &status, WNOHANG, NULL )) > 0 ) {
143	if ( WIFEXITED( status )) {
144	    if ( WEXITSTATUS( status )) {
145		LOG(log_error, logtype_papd, "child %d exited with %d", pid,
146			WEXITSTATUS( status ));
147	    } else {
148		LOG(log_info, logtype_papd, "child %d done", pid );
149	    }
150	} else {
151	    if ( WIFSIGNALED( status )) {
152		LOG(log_error, logtype_papd, "child %d killed with %d", pid,
153			WTERMSIG( status ));
154	    } else {
155		LOG(log_error, logtype_papd, "child %d died", pid );
156	    }
157	}
158    }
159    return;
160}
161
162static char rbuf[ 255 + 1 + 8 ];
163
164int main(int ac, char **av)
165{
166    extern char         *optarg;
167
168    ATP			atp;
169    struct atp_block	atpb;
170    struct sockaddr_at	sat;
171    struct sigaction	sv;
172    struct iovec	iov;
173    fd_set		fdset;
174    struct printer	*pr;
175    char		*p, hostname[ MAXHOSTNAMELEN ];
176    char		cbuf[ 8 ];
177    int			c;
178    char 		*atname;
179
180    if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
181	perror( "gethostname" );
182	exit( 1 );
183    }
184    if (( p = strchr( hostname, '.' )) != NULL ) {
185	*p = '\0';
186    }
187    if (( defprinter.p_name = (char *)malloc( strlen( hostname ) + 1 ))
188	    == NULL ) {
189	perror( "malloc" );
190	exit( 1 );
191    }
192    strcpy( defprinter.p_name, hostname );
193    defprinter.p_type = "LaserWriter";
194    defprinter.p_zone = "*";
195    memset(&defprinter.p_addr, 0, sizeof(defprinter.p_addr));
196#ifdef __svr4__
197    defprinter.p_flags = P_PIPED;
198    defprinter.p_printer = "/usr/bin/lp -T PS";
199#else /* __svr4__ */
200    defprinter.p_flags = P_SPOOLED;
201    defprinter.p_printer = "lp";
202#endif /* __svr4__ */
203    defprinter.p_operator = "operator";
204    defprinter.p_spool = _PATH_PAPDSPOOLDIR;
205#ifdef ABS_PRINT
206    defprinter.p_role = NULL;
207    defprinter.p_srvid = 0;
208#endif /* ABS_PRINT */
209    defprinter.p_pagecost = 200;		/* default cost */
210    defprinter.p_pagecost_msg = NULL;
211    defprinter.p_lock = "lock";
212
213    while (( c = getopt( ac, av, "adf:p:P:v" )) != EOF ) {
214	switch ( c ) {
215	case 'a' :		/* for compatibility with old papd */
216	    break;
217
218	case 'd' :		/* debug */
219	    debug++;
220	    break;
221
222	case 'f' :		/* conffile */
223	    conffile = optarg;
224	    break;
225
226	case 'p' :		/* printcap */
227	    printcap = optarg;
228	    break;
229
230	case 'P' :
231	    pidfile = optarg;
232	    break;
233
234	case 'v' :		/* version */
235	    printf( "papd (version %s)\n", VERSION );
236	    exit ( 1 );
237	    break;
238
239	default :
240	    fprintf( stderr,
241		    "Usage:\t%s [ -d ] [ -f conffile ] [ -p printcap ]\n",
242		    *av );
243	    exit( 1 );
244	}
245    }
246
247
248    switch (server_lock("papd", pidfile, debug)) {
249    case 0: /* open a couple things again in the child */
250      if (!debug && (c = open("/", O_RDONLY)) >= 0) {
251	dup2(c, 1);
252	dup2(c, 2);
253      }
254      break;
255    case -1:
256      exit(1);
257    default:
258      exit(0);
259    }
260
261#ifdef DEBUG1
262    fault_setup(NULL);
263#endif
264
265    /*
266     * Start logging.
267     */
268    if (( p = strrchr( av[ 0 ], '/' )) == NULL ) {
269	p = av[ 0 ];
270    } else {
271	p++;
272    }
273#ifdef ultrix
274    openlog( p, LOG_PID );
275#else /* ultrix */
276    set_processname(p);
277    syslog_setup(log_debug, logtype_default, logoption_ndelay | logoption_pid |
278               debug ? logoption_perror : 0, logfacility_lpr );
279#endif /* ultrix */
280
281    LOG(log_info, logtype_papd, "restart (%s)", version );
282#ifdef HAVE_CUPS
283    LOG(log_info, logtype_papd, "CUPS support enabled (%s)", CUPS_API_VERSION );
284#endif
285
286    getprinters( conffile );
287
288    for ( pr = printers; pr; pr = pr->p_next ) {
289	if (( pr->p_flags & P_SPOOLED ) && rprintcap( pr ) < 0 ) {
290	    LOG(log_error, logtype_papd, "printcap problem: %s", pr->p_printer );
291	}
292
293	if (!(pr->p_flags & P_CUPS)) {
294		if ((size_t)-1 != convert_string_allocate(CH_UNIX, CH_MAC, pr->p_name, -1, &atname)) {
295			pr->p_u_name = pr->p_name;
296			pr->p_name = atname;
297		}
298	}
299
300	if (( pr->p_atp = atp_open( ATADDR_ANYPORT, &pr->p_addr )) == NULL ) {
301	    LOG(log_error, logtype_papd, "atp_open: %s", strerror(errno) );
302	    papd_exit( 1 );
303	}
304	if ( nbp_rgstr( atp_sockaddr( pr->p_atp ), pr->p_name, pr->p_type,
305		pr->p_zone ) < 0 ) {
306	    LOG(log_error, logtype_papd, "can't register %s:%s@%s", pr->p_u_name, pr->p_type,
307		    pr->p_zone );
308	    die( 1 );
309	}
310	if ( pr->p_flags & P_AUTH ) {
311		LOG(log_info, logtype_papd, "Authentication enabled: %s", pr->p_u_name );
312	}
313	else {
314		LOG(log_info, logtype_papd, "Authentication disabled: %s", pr->p_u_name );
315	}
316	LOG(log_info, logtype_papd, "register %s:%s@%s", pr->p_u_name, pr->p_type,
317		pr->p_zone );
318	pr->p_flags |= P_REGISTERED;
319    }
320
321    memset(&sv, 0, sizeof(sv));
322    sv.sa_handler = die;
323    sigemptyset( &sv.sa_mask );
324    sv.sa_flags = SA_RESTART;
325    if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
326	LOG(log_error, logtype_papd, "sigaction: %s", strerror(errno) );
327	papd_exit( 1 );
328    }
329
330    sv.sa_handler = reap;
331    sigemptyset( &sv.sa_mask );
332    sv.sa_flags = SA_RESTART;
333    if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
334	LOG(log_error, logtype_papd, "sigaction: %s", strerror(errno) );
335	papd_exit( 1 );
336    }
337
338    /*
339     * Load UAMS
340     */
341    auth_load(uampath, uamlist);
342
343    /*
344     * Begin accepting connections.
345     */
346    FD_ZERO( &fdset );
347    for (;;) {
348	for ( pr = printers; pr; pr = pr->p_next ) {
349	    FD_SET( atp_fileno( pr->p_atp ), &fdset );
350	}
351	if (( c = select( FD_SETSIZE, &fdset, NULL, NULL, NULL )) < 0 ) {
352	    if ( errno == EINTR ) {
353		continue;
354	    }
355	    LOG(log_error, logtype_papd, "select: %s", strerror(errno) );
356	    papd_exit( 1 );
357	}
358
359	for ( pr = printers; pr; pr = pr->p_next ) {
360	    if ( FD_ISSET( atp_fileno( pr->p_atp ), &fdset )) {
361		int		err = 0;
362
363		memset( &sat, 0, sizeof( struct sockaddr_at ));
364#ifdef BSD4_4
365		sat.sat_len = sizeof( struct sockaddr_at );
366#endif /* BSD4_4 */
367		sat.sat_family = AF_APPLETALK;
368		sat.sat_addr.s_net = ATADDR_ANYNET;
369		sat.sat_addr.s_node = ATADDR_ANYNODE;
370		sat.sat_port = ATADDR_ANYPORT;
371		/* do an atp_rsel(), to prevent hangs */
372		if (( c = atp_rsel( pr->p_atp, &sat, ATP_TREQ )) != ATP_TREQ ) {
373		    continue;
374		}
375		atpb.atp_saddr = &sat;
376		atpb.atp_rreqdata = cbuf;
377		atpb.atp_rreqdlen = sizeof( cbuf );
378		if ( atp_rreq( pr->p_atp, &atpb ) < 0 ) {
379		    LOG(log_error, logtype_papd, "atp_rreq: %s", strerror(errno) );
380		    continue;
381		}
382
383		/* should check length of req buf */
384
385		switch( cbuf[ 1 ] ) {
386		case PAP_OPEN :
387		    connid = (unsigned char)cbuf[ 0 ];
388		    sock = (unsigned char)cbuf[ 4 ];
389		    quantum = (unsigned char)cbuf[ 5 ];
390		    rbuf[ 0 ] = cbuf[ 0 ];
391		    rbuf[ 1 ] = PAP_OPENREPLY;
392		    rbuf[ 2 ] = rbuf[ 3 ] = 0;
393
394		    if (( pr->p_flags & P_SPOOLED ) && rprintcap( pr ) != 0 ) {
395			LOG(log_error, logtype_papd, "printcap problem: %s",
396				pr->p_printer );
397			rbuf[ 2 ] = rbuf[ 3 ] = 0xff;
398			err = 1;
399		    }
400
401#ifdef HAVE_CUPS
402		   /*
403		    * If cups is not accepting jobs, we return
404		    * 0xffff to indicate we're busy
405		    */
406#ifdef DEBUG
407                    LOG(log_debug9, logtype_papd, "CUPS: PAP_OPEN");
408#endif
409		    if ( (pr->p_flags & P_SPOOLED) && (cups_get_printer_status ( pr ) == 0)) {
410                        LOG(log_error, logtype_papd, "CUPS_PAP_OPEN: %s is not accepting jobs",
411                                pr->p_printer );
412                        rbuf[ 2 ] = rbuf[ 3 ] = 0xff;
413                        err = 1;
414                    }
415#endif /* HAVE_CUPS */
416
417		    /*
418		     * If this fails, we've run out of sockets. Rather than
419		     * just die(), let's try to continue. Maybe some sockets
420		     * will close, and we can continue;
421		     */
422		    if (( atp = atp_open( ATADDR_ANYPORT,
423					  &pr->p_addr)) == NULL ) {
424			LOG(log_error, logtype_papd, "atp_open: %s", strerror(errno) );
425			rbuf[ 2 ] = rbuf[ 3 ] = 0xff;  /* printer busy */
426			rbuf[ 4 ] = 0; /* FIXME is it right? */
427			err = 1;
428		    }
429		    else {
430		       rbuf[ 4 ] = atp_sockaddr( atp )->sat_port;
431                    }
432		    rbuf[ 5 ] = oquantum;
433		    rbuf[ 6 ] = rbuf[ 7 ] = 0;
434
435		    iov.iov_base = rbuf;
436		    iov.iov_len = 8 + getstatus( pr, &rbuf[ 8 ] );
437		    atpb.atp_sresiov = &iov;
438		    atpb.atp_sresiovcnt = 1;
439		    /*
440		     * This may error out if we lose a route, so we won't die().
441		     */
442		    if ( atp_sresp( pr->p_atp, &atpb ) < 0 ) {
443			LOG(log_error, logtype_papd, "atp_sresp: %s", strerror(errno) );
444			err = 1;
445		    }
446
447		    if ( err ) {
448			if (atp) {
449			   atp_close(atp);
450                        }
451			continue;
452		    }
453
454		    switch ( c = fork()) {
455		    case -1 :
456			LOG(log_error, logtype_papd, "fork: %s", strerror(errno) );
457                        atp_close(atp);
458			continue;
459
460		    case 0 : /* child */
461			printer = pr;
462
463			#ifndef HAVE_CUPS
464			if (( printer->p_flags & P_SPOOLED ) &&
465				chdir( printer->p_spool ) < 0 ) {
466			    LOG(log_error, logtype_papd, "chdir %s: %s", printer->p_spool, strerror(errno) );
467			    exit( 1 );
468			}
469			#else
470			if (( printer->p_flags & P_SPOOLED ) &&
471				chdir( SPOOLDIR ) < 0 ) {
472			    LOG(log_error, logtype_papd, "chdir %s: %s", SPOOLDIR, strerror(errno) );
473			    exit( 1 );
474			}
475
476			#endif
477
478			sv.sa_handler = SIG_DFL;
479			sigemptyset( &sv.sa_mask );
480			sv.sa_flags = SA_RESTART;
481			if ( sigaction( SIGTERM, &sv, NULL ) < 0 ) {
482			    LOG(log_error, logtype_papd, "sigaction: %s", strerror(errno) );
483			    exit( 1 );
484			}
485
486			if ( sigaction( SIGCHLD, &sv, NULL ) < 0 ) {
487			    LOG(log_error, logtype_papd, "sigaction: %s", strerror(errno) );
488			    exit( 1 );
489                        }
490
491			for ( pr = printers; pr; pr = pr->p_next ) {
492			    atp_close( pr->p_atp );
493			}
494			sat.sat_port = sock;
495			if ( session( atp, &sat ) < 0 ) {
496			    LOG(log_error, logtype_papd, "bad session" );
497			    exit( 1 );
498			}
499			exit( 0 );
500			break;
501
502		    default : /* parent */
503			LOG(log_info, logtype_papd, "child %d for \"%s\" from %u.%u",
504				c, pr->p_name, ntohs( sat.sat_addr.s_net ),
505				sat.sat_addr.s_node);
506			atp_close( atp );
507		    }
508		    break;
509
510		case PAP_SENDSTATUS :
511		    rbuf[ 0 ] = 0;
512		    rbuf[ 1 ] = PAP_STATUS;
513		    rbuf[ 2 ] = rbuf[ 3 ] = 0;
514		    rbuf[ 4 ] = rbuf[ 5 ] = 0;
515		    rbuf[ 6 ] = rbuf[ 7 ] = 0;
516
517		    iov.iov_base = rbuf;
518		    iov.iov_len = 8 + getstatus( pr, &rbuf[ 8 ] );
519		    atpb.atp_sresiov = &iov;
520		    atpb.atp_sresiovcnt = 1;
521		    /*
522		     * This may error out if we lose a route, so we won't die().
523		     */
524		    if ( atp_sresp( pr->p_atp, &atpb ) < 0 ) {
525			LOG(log_error, logtype_papd, "atp_sresp: %s", strerror(errno) );
526		    }
527		    break;
528
529		default :
530		    LOG(log_error, logtype_papd, "Bad request from %u.%u!",
531			    ntohs( sat.sat_addr.s_net ), sat.sat_addr.s_node );
532		    continue;
533		    break;
534		}
535
536#ifdef notdef
537		/*
538		 * Sometimes the child process will send its first READ
539		 * before the parent has sent the OPEN REPLY.  Moving this
540		 * code into the OPEN/STATUS switch fixes this problem.
541		 */
542		iov.iov_base = rbuf;
543		iov.iov_len = 8 + getstatus( pr, &rbuf[ 8 ] );
544		atpb.atp_sresiov = &iov;
545		atpb.atp_sresiovcnt = 1;
546		/*
547		 * This may error out if we lose a route, so we won't die().
548		 */
549		if ( atp_sresp( pr->p_atp, &atpb ) < 0 ) {
550		    LOG(log_error, logtype_papd, "atp_sresp: %s", strerror(errno) );
551		}
552#endif /* notdef */
553	    }
554	}
555    }
556    return 0;
557}
558
559/*
560 * We assume buf is big enough for 255 bytes of data and a length byte.
561 */
562
563int getstatus(struct printer *pr, char *buf)
564{
565
566#ifdef HAVE_CUPS
567    if ( pr->p_flags & P_PIPED ) {
568	*buf = strlen( cannedstatus );
569	strncpy( &buf[ 1 ], cannedstatus, *buf );
570	return( *buf + 1 );
571    } else {
572	cups_get_printer_status( pr );
573	*buf = strlen ( pr->p_status );
574	strncpy ( &buf[1], pr->p_status, *buf);
575	return ( *buf + 1);
576    }
577#else
578
579    char		path[ MAXPATHLEN ];
580    int			fd = -1, rc;
581
582    if ( pr->p_flags & P_SPOOLED && ( pr->p_spool != NULL )) {
583	strcpy( path, pr->p_spool );
584	strcat( path, "/status" );
585	fd = open( path, O_RDONLY);
586    }
587
588    if (( pr->p_flags & P_PIPED ) || ( fd < 0 )) {
589	*buf = strlen( cannedstatus );
590	strncpy( &buf[ 1 ], cannedstatus, *buf );
591	return( *buf + 1 );
592    } else {
593	if (( rc = read( fd, &buf[ 1 ], 255 )) < 0 ) {
594	    rc = 0;
595	}
596	close( fd );
597	if ( rc && buf[ rc ] == '\n' ) {	/* remove trailing newline */
598	    rc--;
599	}
600	*buf = rc;
601	return( rc + 1 );
602    }
603#endif /* HAVE_CUPS */
604}
605
606char	*pgetstr(char *id, char **area);
607char	*getpname(char **area, int bufsize);
608
609#define PF_CONFBUFFER	1024
610
611static void getprinters( char *cf)
612{
613    char		buf[ PF_CONFBUFFER ], area[ PF_CONFBUFFER ], *a, *p, *name, *type, *zone;
614    struct printer	*pr;
615    int			c;
616
617    while (( c = getprent( cf, buf, PF_CONFBUFFER )) > 0 ) {
618	a = area;
619	/*
620	 * Get the printer's nbp name.
621	 */
622	if (( p = getpname( &a, PF_CONFBUFFER )) == NULL ) {
623	    fprintf( stderr, "No printer name\n" );
624	    exit( 1 );
625	}
626
627	if (( pr = (struct printer *)malloc( sizeof( struct printer )))
628		== NULL ) {
629	    perror( "malloc" );
630	    exit( 1 );
631	}
632	memset( pr, 0, sizeof( struct printer ));
633
634	name = defprinter.p_name;
635	type = defprinter.p_type;
636	zone = defprinter.p_zone;
637	if ( nbp_name( p, &name, &type, &zone )) {
638	    fprintf( stderr, "Can't parse \"%s\"\n", name );
639	    exit( 1 );
640	}
641	if ( name != defprinter.p_name ) {
642	    if (( pr->p_name = (char *)malloc( strlen( name ) + 1 )) == NULL ) {
643		perror( "malloc" );
644		exit( 1 );
645	    }
646	    strcpy( pr->p_name, name );
647	} else {
648	    pr->p_name = name;
649	}
650	if ( type != defprinter.p_type ) {
651	    if (( pr->p_type = (char *)malloc( strlen( type ) + 1 )) == NULL ) {
652		perror( "malloc" );
653		exit( 1 );
654	    }
655	    strcpy( pr->p_type, type );
656	} else {
657	    pr->p_type = type;
658	}
659	if ( zone != defprinter.p_zone ) {
660	    if (( pr->p_zone = (char *)malloc( strlen( zone ) + 1 )) == NULL ) {
661		perror( "malloc" );
662		exit( 1 );
663	    }
664	    strcpy( pr->p_zone, zone );
665	} else {
666	    pr->p_zone = zone;
667	}
668
669	if ( pnchktc( cf ) != 1 ) {
670	    fprintf( stderr, "Bad papcap entry\n" );
671	    exit( 1 );
672	}
673
674	/*
675	 * Get PPD file.
676	 */
677	if (( p = pgetstr( "pd", &a ) )) {
678	    if (( pr->p_ppdfile = (char *)malloc( strlen( p ) + 1 )) == NULL ) {
679		perror( "malloc" );
680		exit( 1 );
681	    }
682	    strcpy( pr->p_ppdfile, p );
683	}
684
685	/*
686	 * Get lpd printer name.
687	 */
688	if (( p = pgetstr( "pr", &a )) == NULL ) {
689	    pr->p_printer = defprinter.p_printer;
690	    pr->p_flags = defprinter.p_flags;
691	} else {
692	    if ( *p == '|' ) {
693		p++;
694		pr->p_flags = P_PIPED;
695	    } else {
696		pr->p_flags = P_SPOOLED;
697	    }
698	    if (( pr->p_printer = (char *)malloc( strlen( p ) + 1 )) == NULL ) {
699		perror( "malloc" );
700		exit( 1 );
701	    }
702	    strcpy( pr->p_printer, p );
703	}
704
705	/*
706	 * Do we want authenticated printing?
707	 */
708	if ((p = pgetstr( "ca", &a )) != NULL ) {
709	    if ((pr->p_authprintdir = (char *)malloc(strlen(p)+1)) == NULL) {
710		perror( "malloc" );
711		exit(1);
712	    }
713	    strcpy( pr->p_authprintdir, p );
714	    pr->p_flags |= P_AUTH;
715	    pr->p_flags |= P_AUTH_CAP;
716	} else { pr->p_authprintdir = NULL; }
717
718	if ( pgetflag( "sp" ) == 1 ) {
719	    pr->p_flags |= P_AUTH;
720	    pr->p_flags |= P_AUTH_PSSP;
721	}
722
723	if ((p = pgetstr("am", &a)) != NULL ) {
724		if ((uamlist = (char *)malloc(strlen(p)+1)) == NULL ) {
725			perror("malloc");
726			exit(1);
727		}
728		strcpy(uamlist, p);
729	}
730
731	if ( pr->p_flags & P_SPOOLED ) {
732	    /*
733	     * Get operator name.
734	     */
735	    if (( p = pgetstr( "op", &a )) == NULL ) {
736		pr->p_operator = defprinter.p_operator;
737	    } else {
738		if (( pr->p_operator = (char *)malloc( strlen( p ) + 1 ))
739			== NULL ) {
740		    perror( "malloc" );
741		    exit( 1 );
742		}
743		strcpy( pr->p_operator, p );
744	    }
745	}
746
747	/* get printer's appletalk address. */
748	if (( p = pgetstr( "pa", &a )) == NULL )
749	    memcpy(&pr->p_addr, &defprinter.p_addr, sizeof(pr->p_addr));
750	else
751	    atalk_aton(p, &pr->p_addr);
752
753#ifdef HAVE_CUPS
754	if ((p = pgetstr("co", &a)) != NULL ) {
755            pr->p_cupsoptions = strdup(p);
756            LOG (log_error, logtype_papd, "enabling cups-options for %s: %s", pr->p_name, pr->p_cupsoptions);
757	}
758#endif
759
760	/* convert line endings for setup sections.
761           real ugly work around for foomatic deficiencies,
762	   need to get rid of this */
763	if ( pgetflag("fo") == 1 ) {
764            pr->p_flags |= P_FOOMATIC_HACK;
765            LOG (log_error, logtype_papd, "enabling foomatic hack for %s", pr->p_name);
766	}
767
768	if (strncasecmp (pr->p_name, "cupsautoadd", 11) == 0)
769	{
770#ifdef HAVE_CUPS
771		pr = cups_autoadd_printers (pr, printers);
772		printers = pr;
773#else
774		LOG (log_error, logtype_papd, "cupsautoadd: Cups support not compiled in");
775#endif /* HAVE_CUPS */
776	}
777	else {
778#ifdef HAVE_CUPS
779		if ( cups_check_printer ( pr, printers, 1) == 0)
780		{
781			pr->p_next = printers;
782			printers = pr;
783		}
784#else
785		pr->p_next = printers;
786		printers = pr;
787#endif /* HAVE_CUPS */
788	}
789    }
790    if ( c == 0 ) {
791	endprent();
792    } else {			/* No capability file, do default */
793	printers = &defprinter;
794    }
795}
796
797int rprintcap( struct printer *pr)
798{
799
800#ifdef HAVE_CUPS
801
802    char		*p;
803
804    if ( pr->p_flags & P_SPOOLED && !(pr->p_flags & P_CUPS_AUTOADDED) ) { /* Skip check if autoadded */
805	if ( cups_printername_ok ( pr->p_printer ) != 1) {
806	    LOG(log_error, logtype_papd, "No such CUPS printer: '%s'", pr->p_printer );
807	    return( -1 );
808	}
809    }
810
811    /*
812     * Check for ppd file, moved here because of cups_autoadd we cannot check at the usual location
813     */
814
815    if ( pr->p_ppdfile == NULL ) {
816	if ( (p = (char *) cups_get_printer_ppd ( pr->p_printer )) != NULL ) {
817	    if (( pr->p_ppdfile = (char *)malloc( strlen( p ) + 1 )) == NULL ) {
818	    	LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
819		exit( 1 );
820	    }
821	    strcpy( pr->p_ppdfile, p );
822	    pr->p_flags |= P_CUPS_PPD;
823	    LOG(log_info, logtype_papd, "PPD File for %s set to %s", pr->p_printer, pr->p_ppdfile );
824	}
825    }
826
827
828#else
829
830    char		buf[ 1024 ], area[ 1024 ], *a, *p;
831    int			c;
832
833    /*
834     * Spool directory from printcap file.
835     */
836    if ( pr->p_flags & P_SPOOLED ) {
837	if ( pgetent( printcap, buf, pr->p_printer ) != 1 ) {
838	    LOG(log_error, logtype_papd, "No such printer: %s", pr->p_printer );
839	    return( -1 );
840	}
841
842	/*
843	 * Spool directory.
844	 */
845	if ( pr->p_spool != NULL && pr->p_spool != defprinter.p_spool ) {
846	    free( pr->p_spool );
847	}
848	a = area;
849	if (( p = pgetstr( "sd", &a )) == NULL ) {
850	    pr->p_spool = defprinter.p_spool;
851	} else {
852	    if (( pr->p_spool = (char *)malloc( strlen( p ) + 1 )) == NULL ) {
853		LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
854		exit( 1 );
855	    }
856	    strcpy( pr->p_spool, p );
857	}
858
859	/*
860	 * Is accounting on?
861	 */
862	a = area;
863	if ( pgetstr( "af", &a ) == NULL ) {
864	    pr->p_flags &= ~P_ACCOUNT;
865	} else {
866	    pr->p_flags |= P_ACCOUNT;
867#ifdef ABS_PRINT
868	    if ( pr->p_role != NULL && pr->p_role != defprinter.p_role ) {
869		free( pr->p_role );
870	    }
871	    a = area;
872	    if (( p = pgetstr( "ro", &a )) == NULL ) {
873		pr->p_role = defprinter.p_role;
874	    } else {
875		if (( pr->p_role =
876			(char *)malloc( strlen( p ) + 1 )) == NULL ) {
877		    LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
878		    exit( 1 );
879		}
880		strcpy( pr->p_role, p );
881	    }
882
883	    if (( c = pgetnum( "si" )) < 0 ) {
884		pr->p_srvid = defprinter.p_srvid;
885	    } else {
886		pr->p_srvid = c;
887	    }
888#endif /* ABS_PRINT */
889	}
890
891
892	/*
893	 * Cost of printer.
894	 */
895	if ( pr->p_pagecost_msg != NULL &&
896		pr->p_pagecost_msg != defprinter.p_pagecost_msg ) {
897	    free( pr->p_pagecost_msg );
898	}
899	a = area;
900	if (( p = pgetstr( "pc", &a )) != NULL ) {
901	    if (( pr->p_pagecost_msg =
902		    (char *)malloc( strlen( p ) + 1 )) == NULL ) {
903		LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
904		exit( 1 );
905	    }
906	    strcpy( pr->p_pagecost_msg, p );
907	    pr->p_pagecost = 0;
908	} else if ( pr->p_flags & P_ACCOUNT ) {
909	    if (( c = pgetnum( "pc" )) < 0 ) {
910		pr->p_pagecost = defprinter.p_pagecost;
911	    } else {
912		pr->p_pagecost = c;
913	    }
914	    pr->p_pagecost_msg = NULL;
915	}
916
917	/*
918	 * Get lpd lock file.
919	 */
920	if ( pr->p_lock != NULL && pr->p_lock != defprinter.p_lock ) {
921	    free( pr->p_lock );
922	}
923	a = area;
924	if (( p = pgetstr( "lo", &a )) == NULL ) {
925	    pr->p_lock = defprinter.p_lock;
926	} else {
927	    if (( pr->p_lock = (char *)malloc( strlen( p ) + 1 )) == NULL ) {
928		LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
929		exit( 1 );
930	    }
931	    strcpy( pr->p_lock, p );
932	}
933
934#ifdef KRB
935	/*
936	 * Must Kerberos authenticate?
937	 */
938	if ( pgetflag( "ka" ) == 1 ) {
939	    pr->p_flags |= P_KRB;
940	} else {
941	    pr->p_flags &= ~P_KRB;
942	}
943#endif /* KRB */
944
945	endprent();
946    }
947#endif /* HAVE_CUPS */
948
949    return( 0 );
950}
951