]> arthur.barton.de Git - netatalk.git/blob - etc/papd/lp.c
prototyping to allow the compiler to do some real argument checking
[netatalk.git] / etc / papd / lp.c
1 /*
2  * Copyright (c) 1990,1994 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  *
5  * Portions:
6  * Copyright (c) 1983 Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the University of
20  *      California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37
38 /*
39  * Interface to lpr system.
40  */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include <sys/param.h>
47 #include <sys/syslog.h>
48 #include <sys/time.h>
49 #include <sys/socket.h>
50 #include <sys/stat.h>
51 #include <ctype.h>
52 #include <unistd.h>
53
54 #if defined( sun ) && defined( __svr4__ )
55 #include </usr/ucbinclude/sys/file.h>
56 #else sun __svr4__
57 #include <sys/file.h>
58 #endif sun __svr4__
59 #include <sys/un.h>
60 #include <netinet/in.h>
61 #undef s_net
62 #include <netatalk/at.h>
63 #include <atalk/atp.h>
64 #include <atalk/paths.h>
65
66 #ifdef ABS_PRINT
67 #include <math.h>
68 #endif ABS_PRINT
69
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <netdb.h>
74 #include <fcntl.h>
75 #include <pwd.h>
76
77 #include "printer.h"
78 #include "file.h"
79 #include "lp.h"
80
81 /* These functions aren't used outside of lp.c */
82 int lp_conn_inet();
83 int lp_disconn_inet( int );
84 int lp_conn_unix();
85 int lp_disconn_unix( int );
86
87 char    hostname[ MAXHOSTNAMELEN ];
88
89 extern struct sockaddr_at *sat;
90
91 struct lp {
92     int                 lp_flags;
93     FILE                *lp_stream;
94     int                 lp_seq;
95     char                lp_letter;
96     char                *lp_person;
97     char                *lp_host;
98     char                *lp_job;
99 } lp;
100 #define LP_INIT         (1<<0)
101 #define LP_OPEN         (1<<1)
102 #define LP_PIPE         (1<<2)
103 #define LP_CONNECT      (1<<3)
104 #define LP_QUEUE        (1<<4)
105
106 void lp_person( person )
107     char        *person;
108 {
109     if ( lp.lp_person != NULL ) {
110         free( lp.lp_person );
111     }
112     if (( lp.lp_person = (char *)malloc( strlen( person ) + 1 )) == NULL ) {
113         syslog( LOG_ERR, "malloc: %m" );
114         exit( 1 );
115     }
116     strcpy( lp.lp_person, person );
117 }
118
119 #ifdef ABS_PRINT
120 int lp_pagecost()
121 {
122     char        cost[ 22 ];
123     char        balance[ 22 ];
124     int         err;
125
126     if ( lp.lp_person == NULL ) {
127         return( -1 );
128     }
129     err = ABS_canprint( lp.lp_person, printer->p_role, printer->p_srvid,
130             cost, balance );
131     printer->p_pagecost = floor( atof( cost ) * 10000.0 );
132     printer->p_balance = atof( balance ) + atof( cost );
133     return( err < 0 ? -1 : 0 );
134 }
135 #endif ABS_PRINT
136
137 void lp_host( host )
138     char        *host;
139 {
140     if ( lp.lp_host != NULL ) {
141         free( lp.lp_host );
142     }
143     if (( lp.lp_host = (char *)malloc( strlen( host ) + 1 )) == NULL ) {
144         syslog( LOG_ERR, "malloc: %m" );
145         exit( 1 );
146     }
147     strcpy( lp.lp_host, host );
148 }
149
150 void lp_job( job )
151     char        *job;
152 {
153     char        *p, *q;
154
155     if ( lp.lp_job != NULL ) {
156         free( lp.lp_job );
157     }
158     if (( lp.lp_job = (char *)malloc( strlen( job ) + 1 )) == NULL ) {
159         syslog( LOG_ERR, "malloc: %m" );
160         exit( 1 );
161     }
162     for ( p = job, q = lp.lp_job; *p != '\0'; p++, q++ ) {
163         if ( !isascii( *p ) || !isprint( *p ) || *p == '\\' ) {
164             *q = '.';
165         } else {
166             *q = *p;
167         }
168     }
169     *q = '\0';
170 }
171
172 int lp_init( out, sat )
173     struct papfile      *out;
174     struct sockaddr_at  *sat;
175 {
176     int         fd, n, len;
177     char        *cp, buf[ BUFSIZ ];
178     struct stat st;
179     int         authenticated = 0;
180 #ifdef ABS_PRINT
181     char        cost[ 22 ];
182     char        balance[ 22 ];
183 #endif ABS_PRINT
184
185     if ( printer->p_flags & P_AUTH ) {
186         authenticated = 0;
187
188         /* cap style "log on to afp server before printing" authentication */
189
190         if ( printer->p_authprintdir && (printer->p_flags & P_AUTH_CAP) ) {
191             int addr_net = ntohs( sat->sat_addr.s_net );
192             int addr_node  = sat->sat_addr.s_node;
193             char addr_filename[256];
194             char username[32];
195             struct stat cap_st;
196             FILE *cap_file;
197
198             sprintf(addr_filename, "%s/net%d.%dnode%d", 
199                 printer->p_authprintdir, addr_net/256, addr_net%256, 
200                 addr_node);
201             if (stat(addr_filename, &cap_st) == 0) {
202                 if ((cap_file = fopen(addr_filename, "r")) != NULL) {
203                     if (fscanf(cap_file, "%s", username) != EOF) {
204                         if (getpwnam(username) != NULL ) {
205                             syslog(LOG_INFO, "CAP authenticated %s", username);
206                             lp_person(username);
207                             authenticated = 1;
208                         } else {
209                             syslog(LOG_INFO, "CAP error: invalid username: '%s'", username);
210                         }
211                     } else {
212                         syslog(LOG_INFO, "CAP error: could not read username");
213                     }
214                 } else {
215                     syslog(LOG_INFO, "CAP error: %m");
216                 }
217             } else {
218                 syslog(LOG_INFO, "CAP error: %m");
219             }
220         }
221
222         if ( printer->p_flags & P_AUTH_PSSP ) {
223             if ( lp.lp_person != NULL ) {
224                 authenticated = 1;
225             }
226         }
227
228         if ( authenticated == 0 ) {
229             syslog( LOG_ERR, "lp_init: must authenticate" );
230             spoolerror( out, "Authentication required." );
231             return( -1 );
232         }
233
234 #ifdef ABS_PRINT
235         if (( printer->p_flags & P_ACCOUNT ) && printer->p_pagecost > 0 &&
236                 ! ABS_canprint( lp.lp_person, printer->p_role,
237                 printer->p_srvid, cost, balance )) {
238             syslog( LOG_ERR, "lp_init: no ABS funds" );
239             spoolerror( out, "No ABS funds available." );
240             return( -1 );
241         }
242 #endif ABS_PRINT
243     }
244
245     if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
246         syslog( LOG_ERR, "gethostname: %m" );
247         exit( 1 );
248     }
249
250     if ( lp.lp_flags & LP_INIT ) {
251         syslog( LOG_ERR, "lp_init: already inited, die!" );
252         abort();
253     }
254
255     lp.lp_flags = 0;
256     lp.lp_stream = NULL;
257     lp.lp_letter = 'A';
258
259     if ( printer->p_flags & P_SPOOLED ) {
260         /* check if queuing is enabled: mode & 010 on lock file */
261         if ( stat( printer->p_lock, &st ) < 0 ) {
262             syslog( LOG_ERR, "lp_init: %s: %m", printer->p_lock );
263             spoolerror( out, NULL );
264             return( -1 );
265         }
266         if ( st.st_mode & 010 ) {
267             syslog( LOG_INFO, "lp_init: queuing is disabled" );
268             spoolerror( out, "Queuing is disabled." );
269             return( -1 );
270         }
271
272         if (( fd = open( ".seq", O_RDWR|O_CREAT, 0661 )) < 0 ) {
273             syslog( LOG_ERR, "lp_init: can't create .seq" );
274             spoolerror( out, NULL );
275             return( -1 );
276         }
277
278         if ( flock( fd, LOCK_EX ) < 0 ) {
279             syslog( LOG_ERR, "lp_init: can't lock .seq" );
280             spoolerror( out, NULL );
281             return( -1 );
282         }
283
284         n = 0;
285         if (( len = read( fd, buf, sizeof( buf ))) < 0 ) {
286             syslog( LOG_ERR, "lp_init read: %m" );
287             spoolerror( out, NULL );
288             return( -1 );
289         }
290         if ( len > 0 ) {
291             for ( cp = buf; len; len--, cp++ ) {
292                 if ( *cp < '0' || *cp > '9' ) {
293                     break;
294                 }
295                 n = n * 10 + ( *cp - '0' );
296             }
297         }
298         lp.lp_seq = n;
299
300         n = ( n + 1 ) % 1000;
301         sprintf( buf, "%03d\n", n );
302         lseek( fd, 0L, 0 );
303         write( fd, buf, strlen( buf ));
304         close( fd );
305     } else {
306         lp.lp_flags |= LP_PIPE;
307         lp.lp_seq = getpid();
308     }
309
310     lp.lp_flags |= LP_INIT;
311     return( 0 );
312 }
313
314 int lp_open( out, sat )
315     struct papfile      *out;
316     struct sockaddr_at  *sat;
317 {
318     char        name[ MAXPATHLEN ];
319     int         fd;
320     struct passwd       *pwent;
321
322     if (( lp.lp_flags & LP_INIT ) == 0 && lp_init( out, sat ) != 0 ) {
323         return( -1 );
324     }
325     if ( lp.lp_flags & LP_OPEN ) {
326         syslog( LOG_ERR, "lp_open already open" );
327         abort();
328     }
329
330     if ( lp.lp_flags & LP_PIPE ) {
331         /* go right to program */
332         if (lp.lp_person != NULL) {
333             if((pwent = getpwnam(lp.lp_person)) != NULL) {
334                 if(setreuid(pwent->pw_uid, pwent->pw_uid) != 0) {
335                     syslog(LOG_INFO, "setreuid error: %m");
336                 }
337             } else {
338                 syslog(LOG_INFO, "Error getting username (%s)", lp.lp_person);
339             }
340         }
341         if (( lp.lp_stream = popen( printer->p_printer, "w" )) == NULL ) {
342             syslog( LOG_ERR, "lp_open popen %s: %m", printer->p_printer );
343             spoolerror( out, NULL );
344             return( -1 );
345         }
346     } else {
347         sprintf( name, "df%c%03d%s", lp.lp_letter++, lp.lp_seq, hostname );
348
349         if (( fd = open( name, O_WRONLY|O_CREAT|O_EXCL, 0660 )) < 0 ) {
350             syslog( LOG_ERR, "lp_open %s: %m", name );
351             spoolerror( out, NULL );
352             return( -1 );
353         }
354
355         if (lp.lp_person != NULL) {
356             if ((pwent = getpwnam(lp.lp_person)) == NULL) {
357                 syslog(LOG_ERR, "getpwnam %s: no such user", lp.lp_person);
358                 spoolerror( out, NULL );
359                 return( -1 );
360             }
361         } else {
362             if ((pwent = getpwnam(printer->p_operator)) == NULL) {
363                 syslog(LOG_ERR, "getpwnam %s: no such user", printer->p_operator);
364                 spoolerror( out, NULL );
365                 return( -1 );
366             }
367         }
368
369         if (fchown(fd, pwent->pw_uid, -1) < 0) {
370             syslog(LOG_ERR, "chown %s %s: %m", pwent->pw_name, name);
371             spoolerror( out, NULL );
372             return( -1 );
373         }
374
375         if (( lp.lp_stream = fdopen( fd, "w" )) == NULL ) {
376             syslog( LOG_ERR, "lp_open fdopen: %m" );
377             spoolerror( out, NULL );
378             return( -1 );
379         }
380     }
381     lp.lp_flags |= LP_OPEN;
382
383     return( 0 );
384 }
385
386 int lp_close()
387 {
388     if (( lp.lp_flags & LP_INIT ) == 0 || ( lp.lp_flags & LP_OPEN ) == 0 ) {
389         return 0;
390     }
391     fclose( lp.lp_stream );
392     lp.lp_stream = NULL;
393     lp.lp_flags &= ~LP_OPEN;
394     return 0;
395 }
396
397 int lp_write( buf, len )
398     char        *buf;
399     int         len;
400 {
401     if (( lp.lp_flags & LP_OPEN ) == 0 ) {
402         return( -1 );
403     }
404
405     if ( fwrite( buf, 1, len, lp.lp_stream ) != len ) {
406         syslog( LOG_ERR, "lp_write: %m" );
407         abort();
408     }
409     return( 0 );
410 }
411
412 int lp_cancel()
413 {
414     char        name[ MAXPATHLEN ];
415     char        letter;
416
417     if (( lp.lp_flags & LP_INIT ) == 0 || lp.lp_letter == 'A' ) {
418         return 0;
419     }
420
421     if ( lp.lp_flags & LP_OPEN ) {
422         lp_close();
423     }
424
425     for ( letter = 'A'; letter < lp.lp_letter; letter++ ) {
426         sprintf( name, "df%c%03d%s", letter, lp.lp_seq, hostname );
427         if ( unlink( name ) < 0 ) {
428             syslog( LOG_ERR, "lp_cancel unlink %s: %m", name );
429         }
430     }
431
432     return 0;
433 }
434
435 /*
436  * Create printcap control file, signal printer.  Errors here should
437  * remove queue files.
438  *
439  * XXX piped?
440  */
441 int lp_print()
442 {
443     char                buf[ MAXPATHLEN ];
444     char                tfname[ MAXPATHLEN ];
445     char                cfname[ MAXPATHLEN ];
446     char                letter;
447     int                 fd, n, s;
448     FILE                *cfile;
449
450     if (( lp.lp_flags & LP_INIT ) == 0 || lp.lp_letter == 'A' ) {
451         return 0;
452     }
453     lp_close();
454
455     if ( printer->p_flags & P_SPOOLED ) {
456         sprintf( tfname, "tfA%03d%s", lp.lp_seq, hostname );
457         if (( fd = open( tfname, O_WRONLY|O_EXCL|O_CREAT, 0660 )) < 0 ) {
458             syslog( LOG_ERR, "lp_print %s: %m", tfname );
459             return 0;
460         }
461         if (( cfile = fdopen( fd, "w" )) == NULL ) {
462             syslog( LOG_ERR, "lp_print %s: %m", tfname );
463             return 0;
464         }
465         fprintf( cfile, "H%s\n", hostname );    /* XXX lp_host? */
466
467         if ( lp.lp_person ) {
468             fprintf( cfile, "P%s\n", lp.lp_person );
469         } else {
470             fprintf( cfile, "P%s\n", printer->p_operator );
471         }
472
473         if ( lp.lp_job && *lp.lp_job ) {
474             fprintf( cfile, "J%s\n", lp.lp_job );
475             fprintf( cfile, "T%s\n", lp.lp_job );
476         } else {
477             fprintf( cfile, "JMac Job\n" );
478             fprintf( cfile, "TMac Job\n" );
479         }
480
481         fprintf( cfile, "C%s\n", hostname );    /* XXX lp_host? */
482
483         if ( lp.lp_person ) {
484             fprintf( cfile, "L%s\n", lp.lp_person );
485         } else {
486             fprintf( cfile, "L%s\n", printer->p_operator );
487         }
488
489         for ( letter = 'A'; letter < lp.lp_letter; letter++ ) {
490             fprintf( cfile, "fdf%c%03d%s\n", letter, lp.lp_seq, hostname );
491             fprintf( cfile, "Udf%c%03d%s\n", letter, lp.lp_seq, hostname );
492         }
493
494         if ( lp.lp_job && *lp.lp_job ) {
495             fprintf( cfile, "N%s\n", lp.lp_job );
496         } else {
497             fprintf( cfile, "NMac Job\n" );
498         }
499         fclose( cfile );
500
501         sprintf( cfname, "cfA%03d%s", lp.lp_seq, hostname );
502         if ( link( tfname, cfname ) < 0 ) {
503             syslog( LOG_ERR, "lp_print can't link %s to %s: %m", cfname,
504                     tfname );
505             return 0;
506         }
507         unlink( tfname );
508
509         if (( s = lp_conn_unix()) < 0 ) {
510             syslog( LOG_ERR, "lp_print: lp_conn_unix: %m" );
511             return 0;
512         }
513
514         sprintf( buf, "\1%s\n", printer->p_printer );
515         n = strlen( buf );
516         if ( write( s, buf, n ) != n ) {
517             syslog( LOG_ERR, "lp_print write: %m" );
518             return 0;
519         }
520         if ( read( s, buf, 1 ) != 1 ) {
521             syslog( LOG_ERR, "lp_print read: %m" );
522             return 0;
523         }
524
525         lp_disconn_unix( s );
526
527         if ( buf[ 0 ] != '\0' ) {
528             syslog( LOG_ERR, "lp_print lpd said %c: %m", buf[ 0 ] );
529             return 0;
530         }
531     }
532     syslog( LOG_INFO, "lp_print queued" );
533     return 0;
534 }
535
536 int lp_disconn_unix( fd )
537 {
538     return( close( fd ));
539 }
540
541 int lp_conn_unix()
542 {
543     int                 s;
544     struct sockaddr_un  saun;
545
546     if (( s = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0 ) {
547         syslog( LOG_ERR, "lp_conn_unix socket: %m" );
548         return( -1 );
549     }
550     bzero( &saun, sizeof( struct sockaddr_un ));
551     saun.sun_family = AF_UNIX;
552     strcpy( saun.sun_path, _PATH_DEVPRINTER );
553     if ( connect( s, (struct sockaddr *)&saun,
554             strlen( saun.sun_path ) + 2 ) < 0 ) {
555         syslog( LOG_ERR, "lp_conn_unix connect %s: %m", saun.sun_path );
556         close( s );
557         return( -1 );
558     }
559
560     return( s );
561 }
562
563 int lp_disconn_inet( int fd )
564 {
565     return( close( fd ));
566 }
567
568 int lp_conn_inet()
569 {
570     int                 privfd, port = IPPORT_RESERVED - 1;
571     struct sockaddr_in  sin;
572     struct servent      *sp;
573     struct hostent      *hp;
574
575     if (( sp = getservbyname( "printer", "tcp" )) == NULL ) {
576         syslog( LOG_ERR, "printer/tcp: unknown service\n" );
577         return( -1 );
578     }
579
580     if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
581         syslog( LOG_ERR, "gethostname: %m" );
582         exit( 1 );
583     }
584
585     if (( hp = gethostbyname( hostname )) == NULL ) {
586         syslog( LOG_ERR, "%s: unknown host\n", hostname );
587         return( -1 );
588     }
589
590     if (( privfd = rresvport( &port )) < 0 ) {
591         syslog( LOG_ERR, "lp_connect: socket: %m" );
592         close( privfd );
593         return( -1 );
594     }
595
596     bzero( &sin, sizeof( struct sockaddr_in ));
597     sin.sin_family = AF_INET;
598 /*    sin.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); */
599     bcopy( hp->h_addr, &sin.sin_addr, hp->h_length );
600     sin.sin_port = sp->s_port;
601
602     if ( connect( privfd, (struct sockaddr *)&sin,
603             sizeof( struct sockaddr_in )) < 0 ) {
604         syslog( LOG_ERR, "lp_connect: %m" );
605         close( privfd );
606         return( -1 );
607     }
608
609     return( privfd );
610 }
611
612 int lp_rmjob( job )
613     int         job;
614 {
615     char        buf[ 1024 ];
616     int         n, s;
617
618     if (( s = lp_conn_inet()) < 0 ) {
619         syslog( LOG_ERR, "lp_rmjob: %m" );
620         return( -1 );
621     }
622
623     if ( lp.lp_person == NULL ) {
624         return( -1 );
625     }
626
627     sprintf( buf, "\5%s %s %d\n", printer->p_printer, lp.lp_person, job );
628     n = strlen( buf );
629     if ( write( s, buf, n ) != n ) {
630         syslog( LOG_ERR, "lp_rmjob write: %m" );
631         lp_disconn_inet( s );
632         return( -1 );
633     }
634     while (( n = read( s, buf, sizeof( buf ))) > 0 ) {
635         syslog( LOG_DEBUG, "read %.*s", n, buf );
636     }
637
638     lp_disconn_inet( s );
639     return( 0 );
640 }
641
642 char    *kw_rank = "Rank";
643 char    *kw_active = "active";
644
645 char    *tag_rank = "rank: ";
646 char    *tag_owner = "owner: ";
647 char    *tag_job = "job: ";
648 char    *tag_files = "files: ";
649 char    *tag_size = "size: ";
650 char    *tag_status = "status: ";
651
652 int lp_queue( out )
653     struct papfile      *out;
654 {
655     char                        buf[ 1024 ], *start, *stop, *p, *q;
656     int                         linelength, crlflength;
657     static struct papfile       pf;
658     int                         n, len, s;
659         
660     if (( s = lp_conn_unix()) < 0 ) {
661         syslog( LOG_ERR, "lp_queue: %m" );
662         return( -1 );
663     }
664
665     sprintf( buf, "\3%s\n", printer->p_printer );
666     n = strlen( buf );
667     if ( write( s, buf, n ) != n ) {
668         syslog( LOG_ERR, "lp_queue write: %m" );
669         lp_disconn_unix( s );
670         return( -1 );
671     }
672     pf.pf_state = PF_BOT;
673
674     while (( n = read( s, buf, sizeof( buf ))) > 0 ) {
675         append( &pf, buf, n );
676     }
677
678     for (;;) {
679         if ( markline( &pf, &start, &linelength, &crlflength ) > 0 ) {
680             /* parse */
681             stop = start + linelength;
682             for ( p = start; p < stop; p++ ) {
683                 if ( *p == ' ' || *p == '\t' ) {
684                     break;
685                 }
686             }
687             if ( p >= stop ) {
688                 CONSUME( &pf , linelength + crlflength);
689                 continue;
690             }
691
692             /*
693              * Keys: "Rank", a number, "active"
694              * Anything else is status.
695              */
696             len = p - start;
697             if ( len == strlen( kw_rank ) &&
698                     strncmp( kw_rank, start, len ) == 0 ) {
699                 CONSUME( &pf, linelength + crlflength );
700                 continue;
701             }
702             if (( len == strlen( kw_active ) &&
703                     strncmp( kw_active, start, len ) == 0 ) ||
704                     isdigit( *start )) {                /* a job line */
705                 append( out, tag_rank, strlen( tag_rank ));
706                 append( out, start, p - start );
707                 append( out, "\n", 1 );
708
709                 for ( ; p < stop; p++ ) {
710                     if ( *p != ' ' && *p != '\t' ) {
711                         break;
712                     }
713                 }
714                 for ( q = p; p < stop; p++ ) {
715                     if ( *p == ' ' || *p == '\t' ) {
716                         break;
717                     }
718                 }
719                 if ( p >= stop ) {
720                     append( out, ".\n", 2 );
721                     CONSUME( &pf, linelength + crlflength );
722                     continue;
723                 }
724                 append( out, tag_owner, strlen( tag_owner ));
725                 append( out, q, p - q );
726                 append( out, "\n", 1 );
727
728                 for ( ; p < stop; p++ ) {
729                     if ( *p != ' ' && *p != '\t' ) {
730                         break;
731                     }
732                 }
733                 for ( q = p; p < stop; p++ ) {
734                     if ( *p == ' ' || *p == '\t' ) {
735                         break;
736                     }
737                 }
738                 if ( p >= stop ) {
739                     append( out, ".\n", 2 );
740                     CONSUME( &pf , linelength + crlflength );
741                     continue;
742                 }
743                 append( out, tag_job, strlen( tag_job ));
744                 append( out, q, p - q );
745                 append( out, "\n", 1 );
746
747                 for ( ; p < stop; p++ ) {
748                     if ( *p != ' ' && *p != '\t' ) {
749                         break;
750                     }
751                 }
752                 for ( q = p, p = stop; p > q; p-- ) {
753                     if ( *p == ' ' || *p == '\t' ) {
754                         break;
755                     }
756                 }
757                 for ( ; p > q; p-- ) {
758                     if ( *p != ' ' && *p != '\t' ) {
759                         break;
760                     }
761                 }
762                 for ( ; p > q; p-- ) {
763                     if ( *p == ' ' || *p == '\t' ) {
764                         break;
765                     }
766                 }
767                 if ( p <= q ) {
768                     append( out, ".\n", 2 );
769                     CONSUME( &pf, linelength + crlflength );
770                     continue;
771                 }
772                 append( out, tag_files, strlen( tag_files ));
773                 append( out, q, p - q );
774                 append( out, "\n", 1 );
775
776                 for ( ; p < stop; p++ ) {
777                     if ( *p != ' ' && *p != '\t' ) {
778                         break;
779                     }
780                 }
781                 append( out, tag_size, strlen( tag_size ));
782                 append( out, p, stop - p );
783                 append( out, "\n.\n", 3 );
784
785                 CONSUME( &pf, linelength + crlflength );
786                 continue;
787             }
788
789             /* status */
790             append( out, tag_status, strlen( tag_status ));
791             append( out, start, linelength );
792             append( out, "\n.\n", 3 );
793
794             CONSUME( &pf, linelength + crlflength );
795         } else {
796             append( out, "*\n", 2 );
797             lp_disconn_unix( s );
798             return( 0 );
799         }
800     }
801 }