2 * $Id: lp.c,v 1.32 2009-10-29 11:35:58 didg Exp $
4 * Copyright (c) 1990,1994 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
8 * Copyright (c) 1983 Regents of the University of California.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * Interface to lpr system.
46 #endif /* HAVE_CONFIG_H */
48 #include <sys/param.h>
50 #include <sys/socket.h>
55 #endif /* HAVE_UNISTD_H */
59 #include <netinet/in.h>
64 #endif /* ABS_PRINT */
71 #endif /* HAVE_FCNTL_H */
74 #include <atalk/logger.h>
75 #include <netatalk/at.h>
76 #include <atalk/atp.h>
77 #include <atalk/paths.h>
78 #include <atalk/unicode.h>
85 #include "print_cups.h"
89 /* These functions aren't used outside of lp.c */
91 int lp_disconn_inet( int );
93 int lp_disconn_unix( int );
95 static char hostname[ MAXHOSTNAMELEN ];
97 extern struct sockaddr_at *sat;
106 char *lp_created_for; /* Holds the content of the Postscript %%For Comment if available */
111 #define LP_INIT (1<<0)
112 #define LP_OPEN (1<<1)
113 #define LP_PIPE (1<<2)
114 #define LP_CONNECT (1<<3)
115 #define LP_QUEUE (1<<4)
116 #define LP_JOBPENDING (1<<5)
118 void lp_origin (int origin)
120 lp.lp_origin = origin;
123 /* the converted string should always be shorter, but ... FIXME! */
124 static void convert_octal (char *string, charset_t dest)
126 unsigned char *p, *q;
130 q=p=(unsigned char *)string;
131 while ( *p != '\0' ) {
135 if (dest && isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+2)) ) {
140 ch = strtol( temp, NULL, 8);
141 if ( ch && ch < 0xff)
160 static void translate(charset_t from, charset_t dest, char **option)
164 if (*option != NULL) {
165 convert_octal(*option, from);
167 if ((size_t) -1 != (convert_string_allocate(from, dest, *option, -1, &translated)) ) {
169 *option = translated;
176 static void lp_setup_comments (charset_t dest)
180 switch (lp.lp_origin) {
191 LOG(log_debug, logtype_papd, "job: %s", lp.lp_job );
193 translate(from, dest, &lp.lp_job);
195 if (lp.lp_created_for) {
197 LOG(log_debug, logtype_papd, "for: %s", lp.lp_created_for );
199 translate(from, dest, &lp.lp_created_for);
203 LOG(log_debug, logtype_papd, "person: %s", lp.lp_person );
205 translate(from, dest, &lp.lp_person);
209 #define is_var(a, b) (strncmp((a), (b), 2) == 0)
212 /* removed, it's not used and a pain to get it right from a security POV */
213 static size_t quote(char *dest, char *src, const size_t bsize, size_t len)
217 while (len && used < bsize ) {
223 if (used + 2 > bsize )
239 static char* pipexlate(char *src)
242 static char destbuf[MAXPATHLEN +1];
243 size_t destlen = MAXPATHLEN;
251 memset(dest, 0, MAXPATHLEN +1);
252 if ((p = strchr(src, '%')) == NULL) { /* nothing to do */
253 strncpy(dest, src, MAXPATHLEN);
256 /* first part of the path. copy and forward to the next variable. */
257 len = MIN((size_t)(p - src), destlen);
259 strncpy(dest, src, len);
264 while (p && destlen > 0) {
265 /* now figure out what the variable is */
267 if (is_var(p, "%U")) {
269 } else if (is_var(p, "%C") || is_var(p, "%J") ) {
271 } else if (is_var(p, "%F")) {
272 q = lp.lp_created_for;
273 } else if (is_var(p, "%%")) {
277 /* copy the stuff over. if we don't understand something that we
278 * should, just skip it over. */
280 len = MIN(strlen(q), destlen);
281 len = quote(dest, q, destlen, len);
284 len = MIN(2, destlen);
285 strncpy(dest, q, len);
290 /* stuff up to next % */
292 p = strchr(src, '%');
293 len = p ? MIN((size_t)(p - src), destlen) : destlen;
295 strncpy(dest, src, len);
301 /* reach end of buffer, maybe prematurely, give up */
308 void lp_person(char *person)
310 if ( lp.lp_person != NULL ) {
311 free( lp.lp_person );
313 if (( lp.lp_person = (char *)malloc( strlen( person ) + 1 )) == NULL ) {
314 LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
317 strcpy( lp.lp_person, person );
321 int lp_pagecost(void)
327 if ( lp.lp_person == NULL ) {
330 err = ABS_canprint( lp.lp_person, printer->p_role, printer->p_srvid,
332 printer->p_pagecost = floor( atof( cost ) * 10000.0 );
333 printer->p_balance = atof( balance ) + atof( cost );
334 return( err < 0 ? -1 : 0 );
336 #endif /* ABS_PRINT */
338 void lp_host( char *host)
340 if ( lp.lp_host != NULL ) {
343 if (( lp.lp_host = (char *)malloc( strlen( host ) + 1 )) == NULL ) {
344 LOG(log_error, logtype_papd, "malloc: %s", strerror(errno) );
347 strcpy( lp.lp_host, host );
348 LOG(log_debug, logtype_papd, "host: %s", lp.lp_host );
351 /* Currently lp_job and lp_for will not handle the
352 * conversion of macroman chars > 0x7f correctly
353 * This should be added.
356 void lp_job(char *job)
358 if ( lp.lp_job != NULL ) {
362 lp.lp_job = strdup(job);
364 LOG(log_debug, logtype_papd, "job: %s", lp.lp_job );
369 void lp_for (char *lpfor)
371 if ( lp.lp_created_for != NULL ) {
372 free( lp.lp_created_for );
375 lp.lp_created_for = strdup(lpfor);
379 static int lp_init(struct papfile *out, struct sockaddr_at *sat)
381 int authenticated = 0;
384 char *cp, buf[ BUFSIZ ];
386 #endif /* HAVE_CUPS */
390 #endif /* ABS_PRINT */
392 if ( printer->p_flags & P_AUTH ) {
395 /* cap style "log on to afp server before printing" authentication */
397 if ( printer->p_authprintdir && (printer->p_flags & P_AUTH_CAP) ) {
398 int addr_net = ntohs( sat->sat_addr.s_net );
399 int addr_node = sat->sat_addr.s_node;
400 char addr_filename[256];
401 char auth_string[256];
402 char *username, *afpdpid;
406 memset( auth_string, 0, 256 );
407 sprintf(addr_filename, "%s/net%d.%dnode%d",
408 printer->p_authprintdir, addr_net/256, addr_net%256,
410 if (stat(addr_filename, &cap_st) == 0) {
411 if ((cap_file = fopen(addr_filename, "r")) != NULL) {
412 if (fgets(auth_string, 256, cap_file) != NULL) {
413 username = auth_string;
414 if ((afpdpid = strrchr( auth_string, ':' )) != NULL) {
418 if (getpwnam(username) != NULL ) {
419 LOG(log_info, logtype_papd, "CAP authenticated %s", username);
423 LOG(log_info, logtype_papd, "CAP error: invalid username: '%s'", username);
426 LOG(log_info, logtype_papd, "CAP error: could not read username");
429 LOG(log_info, logtype_papd, "CAP error: %s", strerror(errno));
432 LOG(log_info, logtype_papd, "CAP error: %s", strerror(errno));
436 if ( printer->p_flags & P_AUTH_PSSP ) {
437 if ( lp.lp_person != NULL ) {
442 if ( authenticated == 0 ) {
443 LOG(log_error, logtype_papd, "lp_init: must authenticate" );
444 spoolerror( out, "Authentication required." );
449 if (( printer->p_flags & P_ACCOUNT ) && printer->p_pagecost > 0 &&
450 ! ABS_canprint( lp.lp_person, printer->p_role,
451 printer->p_srvid, cost, balance )) {
452 LOG(log_error, logtype_papd, "lp_init: no ABS funds" );
453 spoolerror( out, "No ABS funds available." );
456 #endif /* ABS_PRINT */
459 if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
460 LOG(log_error, logtype_papd, "gethostname: %s", strerror(errno) );
464 if ( lp.lp_flags & LP_INIT ) {
465 LOG(log_error, logtype_papd, "lp_init: already inited, die!" );
473 if ( printer->p_flags & P_SPOOLED ) {
476 /* check if queuing is enabled: mode & 010 on lock file */
477 if ( stat( printer->p_lock, &st ) < 0 ) {
478 LOG(log_error, logtype_papd, "lp_init: %s: %s", printer->p_lock, strerror(errno) );
479 spoolerror( out, NULL );
482 if ( st.st_mode & 010 ) {
483 LOG(log_info, logtype_papd, "lp_init: queuing is disabled" );
484 spoolerror( out, "Queuing is disabled." );
488 if (( fd = open( ".seq", O_RDWR|O_CREAT, 0661 )) < 0 ) {
489 LOG(log_error, logtype_papd, "lp_init: can't create .seq" );
490 spoolerror( out, NULL );
494 #ifndef SOLARIS /* flock is unsupported, I doubt this stuff works anyway with newer solaris so ignore for now */
495 if ( flock( fd, LOCK_EX ) < 0 ) {
496 LOG(log_error, logtype_papd, "lp_init: can't lock .seq" );
497 spoolerror( out, NULL );
503 if (( len = read( fd, buf, sizeof( buf ))) < 0 ) {
504 LOG(log_error, logtype_papd, "lp_init read: %s", strerror(errno) );
505 spoolerror( out, NULL );
509 for ( cp = buf; len; len--, cp++ ) {
510 if ( *cp < '0' || *cp > '9' ) {
513 n = n * 10 + ( *cp - '0' );
518 n = ( n + 1 ) % 1000;
519 sprintf( buf, "%03d\n", n );
521 write( fd, buf, strlen( buf ));
525 if (cups_get_printer_status ( printer ) == 0)
527 spoolerror( out, "Queuing is disabled." );
531 lp.lp_seq = getpid();
532 #endif /* HAVE CUPS */
534 lp.lp_flags |= LP_PIPE;
535 lp.lp_seq = getpid();
538 lp.lp_flags |= LP_INIT;
542 int lp_open(struct papfile *out, struct sockaddr_at *sat)
544 char name[ MAXPATHLEN ];
546 struct passwd *pwent;
549 LOG (log_debug, logtype_papd, "lp_open");
552 if ( lp.lp_flags & LP_JOBPENDING ) {
556 if (( lp.lp_flags & LP_INIT ) == 0 && lp_init( out, sat ) != 0 ) {
559 if ( lp.lp_flags & LP_OPEN ) {
560 /* LOG(log_error, logtype_papd, "lp_open already open" ); */
565 if ( lp.lp_flags & LP_PIPE ) {
568 /* go right to program */
569 if (lp.lp_person != NULL) {
570 if((pwent = getpwnam(lp.lp_person)) != NULL) {
571 if(setreuid(pwent->pw_uid, pwent->pw_uid) != 0) {
572 LOG(log_error, logtype_papd, "setreuid error: %s", strerror(errno));
576 LOG(log_error, logtype_papd, "Error getting username (%s)", lp.lp_person);
581 lp_setup_comments(CH_UNIX);
582 pipe_cmd = printer->p_printer;
584 LOG(log_error, logtype_papd, "lp_open: no pipe cmd" );
585 spoolerror( out, NULL );
588 if (( lp.lp_stream = popen(pipe_cmd, "w" )) == NULL ) {
589 LOG(log_error, logtype_papd, "lp_open popen %s: %s", printer->p_printer, strerror(errno) );
590 spoolerror( out, NULL );
593 LOG(log_debug, logtype_papd, "lp_open: opened %s", pipe_cmd );
595 sprintf( name, "df%c%03d%s", lp.lp_letter++, lp.lp_seq, hostname );
597 if (( fd = open( name, O_WRONLY|O_CREAT|O_EXCL, 0660 )) < 0 ) {
598 LOG(log_error, logtype_papd, "lp_open %s: %s", name, strerror(errno) );
599 spoolerror( out, NULL );
603 if ( NULL == (lp.lp_spoolfile = (char *) malloc (strlen (name) +1)) ) {
604 LOG(log_error, logtype_papd, "malloc: %s", strerror(errno));
607 strcpy ( lp.lp_spoolfile, name);
609 if (lp.lp_person != NULL) {
610 if ((pwent = getpwnam(lp.lp_person)) == NULL) {
611 LOG(log_error, logtype_papd, "getpwnam %s: no such user", lp.lp_person);
612 spoolerror( out, NULL );
616 if ((pwent = getpwnam(printer->p_operator)) == NULL) {
617 LOG(log_error, logtype_papd, "getpwnam %s: no such user", printer->p_operator);
618 spoolerror( out, NULL );
623 if (fchown(fd, pwent->pw_uid, -1) < 0) {
624 LOG(log_error, logtype_papd, "chown %s %s: %s", pwent->pw_name, name, strerror(errno));
625 spoolerror( out, NULL );
629 if (( lp.lp_stream = fdopen( fd, "w" )) == NULL ) {
630 LOG(log_error, logtype_papd, "lp_open fdopen: %s", strerror(errno) );
631 spoolerror( out, NULL );
635 LOG(log_debug, logtype_papd, "lp_open: opened %s", name );
638 lp.lp_flags |= LP_OPEN;
644 if (( lp.lp_flags & LP_INIT ) == 0 || ( lp.lp_flags & LP_OPEN ) == 0 ) {
647 fclose( lp.lp_stream );
649 lp.lp_flags &= ~LP_OPEN;
650 lp.lp_flags |= LP_JOBPENDING;
656 int lp_write(struct papfile *in, char *buf, size_t len)
658 #define BUFSIZE 32768
659 static char tempbuf[BUFSIZE];
660 static char tempbuf2[BUFSIZE];
661 static size_t bufpos = 0;
662 static int last_line_translated = 1; /* if 0, append a \n a the start */
665 /* Before we write out anything check for a pending job, e.g. cover page */
666 if (lp.lp_flags & LP_JOBPENDING)
669 /* foomatic doesn't handle mac line endings, so we convert them for
670 * the Postscript headers
671 * REALLY ugly hack, remove ASAP again */
672 if ((printer->p_flags & P_FOOMATIC_HACK) && (in->pf_state & PF_TRANSLATE) &&
673 (buf[len-1] != '\n') ) {
674 if (len <= BUFSIZE) {
675 if (!last_line_translated) {
677 memcpy(tempbuf2+1, buf, len++);
680 memcpy(tempbuf2, buf, len);
682 if (tempbuf2[len-1] == '\r')
683 tempbuf2[len-1] = '\n';
686 last_line_translated = 1;
688 LOG(log_debug, logtype_papd, "lp_write: %s", tbuf );
692 LOG(log_error, logtype_papd, "lp_write: conversion buffer too small" );
697 if (printer->p_flags & P_FOOMATIC_HACK && buf[len-1] == '\n') {
698 last_line_translated = 1;
701 last_line_translated = 0;
704 /* To be able to do commandline substitutions on piped printers
705 * we store the start of the print job in a buffer.
706 * %%EndComment triggers writing to file */
707 if (( lp.lp_flags & LP_OPEN ) == 0 ) {
709 LOG(log_debug, logtype_papd, "lp_write: writing to temporary buffer" );
711 if ((bufpos+len) > BUFSIZE) {
712 LOG(log_error, logtype_papd, "lp_write: temporary buffer too small" );
713 /* FIXME: call lp_open here? abort isn't nice... */
717 memcpy(tempbuf + bufpos, tbuf, len);
719 if (bufpos > BUFSIZE/2)
720 in->pf_state |= PF_STW; /* we used half of the buffer, start writing */
725 if ( fwrite( tempbuf, 1, bufpos, lp.lp_stream ) != bufpos ) {
726 LOG(log_error, logtype_papd, "lp_write: %s", strerror(errno) );
732 if ( fwrite( tbuf, 1, len, lp.lp_stream ) != len ) {
733 LOG(log_error, logtype_papd, "lp_write: %s", strerror(errno) );
741 char name[ MAXPATHLEN ];
744 if (( lp.lp_flags & LP_INIT ) == 0 || lp.lp_letter == 'A' ) {
748 if ( lp.lp_flags & LP_OPEN ) {
752 for ( letter = 'A'; letter < lp.lp_letter; letter++ ) {
753 sprintf( name, "df%c%03d%s", letter, lp.lp_seq, hostname );
754 if ( unlink( name ) < 0 ) {
755 LOG(log_error, logtype_papd, "lp_cancel unlink %s: %s", name, strerror(errno) );
763 * Create printcap control file, signal printer. Errors here should
764 * remove queue files.
771 char buf[ MAXPATHLEN ];
772 char tfname[ MAXPATHLEN ];
773 char cfname[ MAXPATHLEN ];
777 #endif /* HAVE_CUPS */
779 if (( lp.lp_flags & LP_INIT ) == 0 || lp.lp_letter == 'A' ) {
783 lp.lp_flags &= ~LP_JOBPENDING;
785 if ( printer->p_flags & P_SPOOLED ) {
787 sprintf( tfname, "tfA%03d%s", lp.lp_seq, hostname );
788 if (( fd = open( tfname, O_WRONLY|O_EXCL|O_CREAT, 0660 )) < 0 ) {
789 LOG(log_error, logtype_papd, "lp_print %s: %s", tfname, strerror(errno) );
792 if (( cfile = fdopen( fd, "w" )) == NULL ) {
793 LOG(log_error, logtype_papd, "lp_print %s: %s", tfname, strerror(errno) );
796 fprintf( cfile, "H%s\n", hostname ); /* XXX lp_host? */
798 if ( lp.lp_person ) {
799 fprintf( cfile, "P%s\n", lp.lp_person );
801 fprintf( cfile, "P%s\n", printer->p_operator );
804 if ( lp.lp_job && *lp.lp_job ) {
805 fprintf( cfile, "J%s\n", lp.lp_job );
806 fprintf( cfile, "T%s\n", lp.lp_job );
808 fprintf( cfile, "JMac Job\n" );
809 fprintf( cfile, "TMac Job\n" );
812 fprintf( cfile, "C%s\n", hostname ); /* XXX lp_host? */
814 if ( lp.lp_person ) {
815 fprintf( cfile, "L%s\n", lp.lp_person );
817 fprintf( cfile, "L%s\n", printer->p_operator );
820 for ( letter = 'A'; letter < lp.lp_letter; letter++ ) {
821 fprintf( cfile, "fdf%c%03d%s\n", letter, lp.lp_seq, hostname );
822 fprintf( cfile, "Udf%c%03d%s\n", letter, lp.lp_seq, hostname );
825 if ( lp.lp_job && *lp.lp_job ) {
826 fprintf( cfile, "N%s\n", lp.lp_job );
828 fprintf( cfile, "NMac Job\n" );
832 sprintf( cfname, "cfA%03d%s", lp.lp_seq, hostname );
833 if ( link( tfname, cfname ) < 0 ) {
834 LOG(log_error, logtype_papd, "lp_print can't link %s to %s: %s", cfname,
835 tfname, strerror(errno) );
840 if (( s = lp_conn_unix()) < 0 ) {
841 LOG(log_error, logtype_papd, "lp_print: lp_conn_unix: %s", strerror(errno) );
845 sprintf( buf, "\1%s\n", printer->p_printer );
847 if ( write( s, buf, n ) != n ) {
848 LOG(log_error, logtype_papd, "lp_print write: %s" , strerror(errno));
851 if ( read( s, buf, 1 ) != 1 ) {
852 LOG(log_error, logtype_papd, "lp_print read: %s" , strerror(errno));
856 lp_disconn_unix( s );
858 if ( buf[ 0 ] != '\0' ) {
859 LOG(log_error, logtype_papd, "lp_print lpd said %c: %s", buf[ 0 ], strerror(errno) );
863 if ( ! (lp.lp_job && *lp.lp_job) ) {
864 lp.lp_job = strdup("Mac Job");
867 lp_setup_comments(add_charset(cups_get_language ()));
869 if (lp.lp_person != NULL) {
870 cups_print_job ( printer->p_printer, lp.lp_spoolfile, lp.lp_job, lp.lp_person, printer->p_cupsoptions);
871 } else if (lp.lp_created_for != NULL) {
872 cups_print_job ( printer->p_printer, lp.lp_spoolfile, lp.lp_job, lp.lp_created_for, printer->p_cupsoptions);
874 cups_print_job ( printer->p_printer, lp.lp_spoolfile, lp.lp_job, printer->p_operator, printer->p_cupsoptions);
877 /*LOG(log_info, logtype_papd, "lp_print unlink %s", lp.lp_spoolfile );*/
878 unlink ( lp.lp_spoolfile );
880 #endif /* HAVE_CUPS*/
882 LOG(log_info, logtype_papd, "lp_print queued" );
887 int lp_disconn_unix( int fd )
889 return( close( fd ));
892 int lp_conn_unix(void)
895 struct sockaddr_un saun;
897 if (( s = socket( AF_UNIX, SOCK_STREAM, 0 )) < 0 ) {
898 LOG(log_error, logtype_papd, "lp_conn_unix socket: %s", strerror(errno) );
901 memset( &saun, 0, sizeof( struct sockaddr_un ));
902 saun.sun_family = AF_UNIX;
903 strcpy( saun.sun_path, _PATH_DEVPRINTER );
904 if ( connect( s, (struct sockaddr *)&saun,
905 strlen( saun.sun_path ) + 2 ) < 0 ) {
906 LOG(log_error, logtype_papd, "lp_conn_unix connect %s: %s", saun.sun_path, strerror(errno) );
914 int lp_disconn_inet( int fd )
916 return( close( fd ));
919 int lp_conn_inet(void)
921 int privfd, port = IPPORT_RESERVED - 1;
922 struct sockaddr_in sin;
926 if (( sp = getservbyname( "printer", "tcp" )) == NULL ) {
927 LOG(log_error, logtype_papd, "printer/tcp: unknown service" );
931 if ( gethostname( hostname, sizeof( hostname )) < 0 ) {
932 LOG(log_error, logtype_papd, "gethostname: %s", strerror(errno) );
936 if (( hp = gethostbyname( hostname )) == NULL ) {
937 LOG(log_error, logtype_papd, "%s: unknown host", hostname );
941 if (( privfd = rresvport( &port )) < 0 ) {
942 LOG(log_error, logtype_papd, "lp_connect: socket: %s", strerror(errno) );
947 memset( &sin, 0, sizeof( struct sockaddr_in ));
948 sin.sin_family = AF_INET;
949 /* sin.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); */
950 memcpy( &sin.sin_addr, hp->h_addr, hp->h_length );
951 sin.sin_port = sp->s_port;
953 if ( connect( privfd, (struct sockaddr *)&sin,
954 sizeof( struct sockaddr_in )) < 0 ) {
955 LOG(log_error, logtype_papd, "lp_connect: %s", strerror(errno) );
963 int lp_rmjob( int job)
968 if (( s = lp_conn_inet()) < 0 ) {
969 LOG(log_error, logtype_papd, "lp_rmjob: %s", strerror(errno) );
973 if ( lp.lp_person == NULL ) {
977 sprintf( buf, "\5%s %s %d\n", printer->p_printer, lp.lp_person, job );
979 if ( write( s, buf, n ) != n ) {
980 LOG(log_error, logtype_papd, "lp_rmjob write: %s", strerror(errno) );
981 lp_disconn_inet( s );
984 while (( n = read( s, buf, sizeof( buf ))) > 0 ) {
985 LOG(log_debug, logtype_papd, "read %.*s", n, buf );
988 lp_disconn_inet( s );
992 char *kw_rank = "Rank";
993 char *kw_active = "active";
995 char *tag_rank = "rank: ";
996 char *tag_owner = "owner: ";
997 char *tag_job = "job: ";
998 char *tag_files = "files: ";
999 char *tag_size = "size: ";
1000 char *tag_status = "status: ";
1002 int lp_queue( struct papfile *out)
1004 char buf[ 1024 ], *start, *stop, *p, *q;
1005 int linelength, crlflength;
1006 static struct papfile pf;
1011 if (( s = lp_conn_unix()) < 0 ) {
1012 LOG(log_error, logtype_papd, "lp_queue: %s", strerror(errno) );
1016 sprintf( buf, "\3%s\n", printer->p_printer );
1018 if ( write( s, buf, n ) != n ) {
1019 LOG(log_error, logtype_papd, "lp_queue write: %s", strerror(errno) );
1020 lp_disconn_unix( s );
1023 pf.pf_state = PF_BOT;
1025 while (( n = read( s, buf, sizeof( buf ))) > 0 ) {
1026 append( &pf, buf, n );
1030 if ( markline( &pf, &start, &linelength, &crlflength ) > 0 ) {
1032 stop = start + linelength;
1033 for ( p = start; p < stop; p++ ) {
1034 if ( *p == ' ' || *p == '\t' ) {
1039 CONSUME( &pf , linelength + crlflength);
1044 * Keys: "Rank", a number, "active"
1045 * Anything else is status.
1048 if ( len == strlen( kw_rank ) &&
1049 strncmp( kw_rank, start, len ) == 0 ) {
1050 CONSUME( &pf, linelength + crlflength );
1053 if (( len == strlen( kw_active ) &&
1054 strncmp( kw_active, start, len ) == 0 ) ||
1055 isdigit( *start )) { /* a job line */
1056 append( out, tag_rank, strlen( tag_rank ));
1057 append( out, start, p - start );
1058 append( out, "\n", 1 );
1060 for ( ; p < stop; p++ ) {
1061 if ( *p != ' ' && *p != '\t' ) {
1065 for ( q = p; p < stop; p++ ) {
1066 if ( *p == ' ' || *p == '\t' ) {
1071 append( out, ".\n", 2 );
1072 CONSUME( &pf, linelength + crlflength );
1075 append( out, tag_owner, strlen( tag_owner ));
1076 append( out, q, p - q );
1077 append( out, "\n", 1 );
1079 for ( ; p < stop; p++ ) {
1080 if ( *p != ' ' && *p != '\t' ) {
1084 for ( q = p; p < stop; p++ ) {
1085 if ( *p == ' ' || *p == '\t' ) {
1090 append( out, ".\n", 2 );
1091 CONSUME( &pf , linelength + crlflength );
1094 append( out, tag_job, strlen( tag_job ));
1095 append( out, q, p - q );
1096 append( out, "\n", 1 );
1098 for ( ; p < stop; p++ ) {
1099 if ( *p != ' ' && *p != '\t' ) {
1103 for ( q = p, p = stop; p > q; p-- ) {
1104 if ( *p == ' ' || *p == '\t' ) {
1108 for ( ; p > q; p-- ) {
1109 if ( *p != ' ' && *p != '\t' ) {
1113 for ( ; p > q; p-- ) {
1114 if ( *p == ' ' || *p == '\t' ) {
1119 append( out, ".\n", 2 );
1120 CONSUME( &pf, linelength + crlflength );
1123 append( out, tag_files, strlen( tag_files ));
1124 append( out, q, p - q );
1125 append( out, "\n", 1 );
1127 for ( ; p < stop; p++ ) {
1128 if ( *p != ' ' && *p != '\t' ) {
1132 append( out, tag_size, strlen( tag_size ));
1133 append( out, p, stop - p );
1134 append( out, "\n.\n", 3 );
1136 CONSUME( &pf, linelength + crlflength );
1141 append( out, tag_status, strlen( tag_status ));
1142 append( out, start, linelength );
1143 append( out, "\n.\n", 3 );
1145 CONSUME( &pf, linelength + crlflength );
1147 append( out, "*\n", 2 );
1148 lp_disconn_unix( s );
1153 #endif /* HAVE_CUPS */