Load cups into easysw/current.
[thirdparty/cups.git] / backend / lpd.c
1 /*
2  * "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $"
3  *
4  *   Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Easy Software Products and are protected by Federal
10  *   copyright law.  Distribution and use rights are outlined in the file
11  *   "LICENSE" which should have been included with this file.  If this
12  *   file is missing or damaged please contact Easy Software Products
13  *   at:
14  *
15  *       Attn: CUPS Licensing Information
16  *       Easy Software Products
17  *       44141 Airport View Drive, Suite 204
18  *       Hollywood, Maryland 20636 USA
19  *
20  *       Voice: (301) 373-9600
21  *       EMail: cups-info@cups.org
22  *         WWW: http://www.cups.org
23  *
24  *   This file is subject to the Apple OS-Developed Software exception.
25  *
26  * Contents:
27  *
28  *   main()            - Send a file to the printer or server.
29  *   lpd_command()     - Send an LPR command sequence and wait for a reply.
30  *   lpd_queue()       - Queue a file using the Line Printer Daemon protocol.
31  *   lpd_timeout()     - Handle timeout alarms...
32  *   lpd_write()       - Write a buffer of data to an LPD server.
33  *   rresvport_af()    - A simple implementation of rresvport_af().
34  *   sigterm_handler() - Handle 'terminate' signals that stop the backend.
35  */
36
37 /*
38  * Include necessary headers.
39  */
40
41 #include <cups/backend.h>
42 #include <cups/http-private.h>
43 #include <cups/cups.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <ctype.h>
48 #include <cups/string.h>
49 #include <errno.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <signal.h>
53
54 #ifdef WIN32
55 #  include <winsock.h>
56 #else
57 #  include <sys/socket.h>
58 #  include <netinet/in.h>
59 #  include <arpa/inet.h>
60 #  include <netdb.h>
61 #endif /* WIN32 */
62
63
64 /*
65  * Globals...
66  */
67
68 static char     tmpfilename[1024] = ""; /* Temporary spool file name */
69 static int      abort_job = 0;          /* Non-zero if we get SIGTERM */
70
71
72 /*
73  * The order for control and data files in LPD requests...
74  */
75
76 #define ORDER_CONTROL_DATA      0       /* Control file first, then data */
77 #define ORDER_DATA_CONTROL      1       /* Data file first, then control */
78
79
80 /*
81  * What to reserve...
82  */
83
84 #define RESERVE_NONE            0       /* Don't reserve a priviledged port */
85 #define RESERVE_RFC1179         1       /* Reserve port 721-731 */
86 #define RESERVE_ANY             2       /* Reserve port 1-1023 */
87
88
89 /*
90  * Local functions...
91  */
92
93 static int      lpd_command(int lpd_fd, int timeout, char *format, ...);
94 static int      lpd_queue(const char *hostname, int port, const char *printer,
95                           const char *filename,
96                           const char *user, const char *title, int copies,
97                           int banner, int format, int order, int reserve,
98                           int manual_copies, int timeout);
99 static void     lpd_timeout(int sig);
100 static int      lpd_write(int lpd_fd, char *buffer, int length);
101 #ifndef HAVE_RRESVPORT_AF
102 static int      rresvport_af(int *port, int family);
103 #endif /* !HAVE_RRESVPORT_AF */
104 static void     sigterm_handler(int sig);
105
106
107 /*
108  * 'main()' - Send a file to the printer or server.
109  *
110  * Usage:
111  *
112  *    printer-uri job-id user title copies options [file]
113  */
114
115 int                                     /* O - Exit status */
116 main(int  argc,                         /* I - Number of command-line arguments (6 or 7) */
117      char *argv[])                      /* I - Command-line arguments */
118 {
119   char                  method[255],    /* Method in URI */
120                         hostname[1024], /* Hostname */
121                         username[255],  /* Username info */
122                         resource[1024], /* Resource info (printer name) */
123                         *options,       /* Pointer to options */
124                         name[255],      /* Name of option */
125                         value[255],     /* Value of option */
126                         *ptr,           /* Pointer into name or value */
127                         *filename,      /* File to print */
128                         title[256];     /* Title string */
129   int                   port;           /* Port number */
130   int                   status;         /* Status of LPD job */
131   int                   banner;         /* Print banner page? */
132   int                   format;         /* Print format */
133   int                   order;          /* Order of control/data files */
134   int                   reserve;        /* Reserve priviledged port? */
135   int                   sanitize_title; /* Sanitize title string? */
136   int                   manual_copies,  /* Do manual copies? */
137                         timeout,        /* Timeout */
138                         copies;         /* Number of copies */
139 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
140   struct sigaction      action;         /* Actions for POSIX signals */
141 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
142
143
144  /*
145   * Make sure status messages are not buffered...
146   */
147
148   setbuf(stderr, NULL);
149
150  /*
151   * Ignore SIGPIPE and catch SIGTERM signals...
152   */
153
154 #ifdef HAVE_SIGSET
155   sigset(SIGPIPE, SIG_IGN);
156   sigset(SIGTERM, sigterm_handler);
157 #elif defined(HAVE_SIGACTION)
158   memset(&action, 0, sizeof(action));
159   action.sa_handler = SIG_IGN;
160   sigaction(SIGPIPE, &action, NULL);
161
162   sigemptyset(&action.sa_mask);
163   sigaddset(&action.sa_mask, SIGTERM);
164   action.sa_handler = sigterm_handler;
165   sigaction(SIGTERM, &action, NULL);
166 #else
167   signal(SIGPIPE, SIG_IGN);
168   signal(SIGTERM, sigterm_handler);
169 #endif /* HAVE_SIGSET */
170
171  /*
172   * Check command-line...
173   */
174
175   if (argc == 1)
176   {
177     puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\"");
178     return (CUPS_BACKEND_OK);
179   }
180   else if (argc < 6 || argc > 7)
181   {
182     fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
183             argv[0]);
184     return (CUPS_BACKEND_FAILED);
185   }
186
187  /*
188   * If we have 7 arguments, print the file named on the command-line.
189   * Otherwise, copy stdin to a temporary file and print the temporary
190   * file.
191   */
192
193   if (argc == 6)
194   {
195    /*
196     * Copy stdin to a temporary file...
197     */
198
199     int  fd;            /* Temporary file */
200     char buffer[8192];  /* Buffer for copying */
201     int  bytes;         /* Number of bytes read */
202
203
204     if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
205     {
206       perror("ERROR: unable to create temporary file");
207       return (CUPS_BACKEND_FAILED);
208     }
209
210     while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
211       if (write(fd, buffer, bytes) < bytes)
212       {
213         perror("ERROR: unable to write to temporary file");
214         close(fd);
215         unlink(tmpfilename);
216         return (CUPS_BACKEND_FAILED);
217       }
218
219     close(fd);
220     filename = tmpfilename;
221   }
222   else
223     filename = argv[6];
224
225  /*
226   * Extract the hostname and printer name from the URI...
227   */
228
229   httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username),
230                   hostname, sizeof(hostname), &port,
231                   resource, sizeof(resource));
232
233   if (!username[0])
234   {
235    /*
236     * If no username is in the device URI, then use the print job user...
237     */
238
239     strlcpy(username, argv[2], sizeof(username));
240   }
241
242  /*
243   * See if there are any options...
244   */
245
246   banner         = 0;
247   format         = 'l';
248   order          = ORDER_CONTROL_DATA;
249   reserve        = RESERVE_ANY;
250   manual_copies  = 1;
251   timeout        = 300;
252   sanitize_title = 1;
253
254 #if defined(__APPLE__)
255   /* We want to pass utf-8 characters, not re-map them (3071945) */
256   sanitize_title= 0;
257 #endif
258
259   if ((options = strchr(resource, '?')) != NULL)
260   {
261    /*
262     * Yup, terminate the device name string and move to the first
263     * character of the options...
264     */
265
266     *options++ = '\0';
267
268    /*
269     * Parse options...
270     */
271
272     while (*options)
273     {
274      /*
275       * Get the name...
276       */
277
278       for (ptr = name; *options && *options != '=';)
279         if (ptr < (name + sizeof(name) - 1))
280           *ptr++ = *options++;
281       *ptr = '\0';
282
283       if (*options == '=')
284       {
285        /*
286         * Get the value...
287         */
288
289         options ++;
290
291         for (ptr = value; *options && *options != '+' && *options != '&';)
292           if (ptr < (value + sizeof(value) - 1))
293             *ptr++ = *options++;
294         *ptr = '\0';
295
296         if (*options == '+')
297           options ++;
298       }
299       else
300         value[0] = '\0';
301
302      /*
303       * Process the option...
304       */
305
306       if (strcasecmp(name, "banner") == 0)
307       {
308        /*
309         * Set the banner...
310         */
311
312         banner = !value[0] ||
313                  strcasecmp(value, "on") == 0 ||
314                  strcasecmp(value, "yes") == 0 ||
315                  strcasecmp(value, "true") == 0;
316       }
317       else if (strcasecmp(name, "format") == 0 && value[0])
318       {
319        /*
320         * Set output format...
321         */
322
323         if (strchr("cdfglnoprtv", value[0]) != NULL)
324           format = value[0];
325         else
326           fprintf(stderr, "ERROR: Unknown format character \"%c\"\n", value[0]);
327       }
328       else if (strcasecmp(name, "order") == 0 && value[0])
329       {
330        /*
331         * Set control/data order...
332         */
333
334         if (strcasecmp(value, "control,data") == 0)
335           order = ORDER_CONTROL_DATA;
336         else if (strcasecmp(value, "data,control") == 0)
337           order = ORDER_DATA_CONTROL;
338         else
339           fprintf(stderr, "ERROR: Unknown file order \"%s\"\n", value);
340       }
341       else if (strcasecmp(name, "reserve") == 0)
342       {
343        /*
344         * Set port reservation mode...
345         */
346
347         if (!value[0] ||
348             !strcasecmp(value, "on") ||
349             !strcasecmp(value, "yes") ||
350             !strcasecmp(value, "true") ||
351             !strcasecmp(value, "rfc1179"))
352           reserve = RESERVE_RFC1179;
353         else if (!strcasecmp(value, "any"))
354           reserve = RESERVE_ANY;
355         else
356           reserve = RESERVE_NONE;
357       }
358       else if (strcasecmp(name, "manual_copies") == 0)
359       {
360        /*
361         * Set manual copies...
362         */
363
364         manual_copies = !value[0] ||
365                         strcasecmp(value, "on") == 0 ||
366                         strcasecmp(value, "yes") == 0 ||
367                         strcasecmp(value, "true") == 0;
368       }
369       else if (strcasecmp(name, "sanitize_title") == 0)
370       {
371        /*
372         * Set sanitize title...
373         */
374
375         sanitize_title = !value[0] ||
376                         strcasecmp(value, "on") == 0 ||
377                         strcasecmp(value, "yes") == 0 ||
378                         strcasecmp(value, "true") == 0;
379       }
380       else if (strcasecmp(name, "timeout") == 0)
381       {
382        /*
383         * Set the timeout...
384         */
385
386         if (atoi(value) > 0)
387           timeout = atoi(value);
388       }
389     }
390   }
391
392  /*
393   * Sanitize the document title...
394   */
395
396   strlcpy(title, argv[3], sizeof(title));
397
398   if (sanitize_title)
399   {
400    /*
401     * Sanitize the title string so that we don't cause problems on
402     * the remote end...
403     */
404
405     for (ptr = title; *ptr; ptr ++)
406       if (!isalnum(*ptr & 255) && !isspace(*ptr & 255))
407         *ptr = '_';
408   }
409
410  /*
411   * Queue the job...
412   */
413
414   if (argc > 6)
415   {
416     if (manual_copies)
417     {
418       manual_copies = atoi(argv[4]);
419       copies        = 1;
420     }
421     else
422     {
423       manual_copies = 1;
424       copies        = atoi(argv[4]);
425     }
426
427     status = lpd_queue(hostname, port, resource + 1, filename,
428                        username, title, copies,
429                        banner, format, order, reserve, manual_copies, timeout);
430
431     if (!status)
432       fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4]));
433   }
434   else
435     status = lpd_queue(hostname, port, resource + 1, filename,
436                        username, title, 1,
437                        banner, format, order, reserve, 1, timeout);
438
439  /*
440   * Remove the temporary file if necessary...
441   */
442
443   if (tmpfilename[0])
444     unlink(tmpfilename);
445
446  /*
447   * Return the queue status...
448   */
449
450   return (status);
451 }
452
453
454 /*
455  * 'lpd_command()' - Send an LPR command sequence and wait for a reply.
456  */
457
458 static int                      /* O - Status of command */
459 lpd_command(int  fd,            /* I - Socket connection to LPD host */
460             int  timeout,       /* I - Seconds to wait for a response */
461             char *format,       /* I - printf()-style format string */
462             ...)                /* I - Additional args as necessary */
463 {
464   va_list       ap;             /* Argument pointer */
465   char          buf[1024];      /* Output buffer */
466   int           bytes;          /* Number of bytes to output */
467   char          status;         /* Status from command */
468
469
470  /*
471   * Don't try to send commands if the job has been cancelled...
472   */
473
474   if (abort_job)
475     return (-1);
476
477  /*
478   * Format the string...
479   */
480
481   va_start(ap, format);
482   bytes = vsnprintf(buf, sizeof(buf), format, ap);
483   va_end(ap);
484
485   fprintf(stderr, "DEBUG: lpd_command %2.2x %s", buf[0], buf + 1);
486
487  /*
488   * Send the command...
489   */
490
491   fprintf(stderr, "DEBUG: Sending command string (%d bytes)...\n", bytes);
492
493   if (lpd_write(fd, buf, bytes) < bytes)
494   {
495     perror("ERROR: Unable to send LPD command");
496     return (-1);
497   }
498
499  /*
500   * Read back the status from the command and return it...
501   */
502
503   fprintf(stderr, "DEBUG: Reading command status...\n");
504
505   alarm(timeout);
506
507   if (recv(fd, &status, 1, 0) < 1)
508   {
509     fprintf(stderr, "WARNING: Remote host did not respond with command "
510                     "status byte after %d seconds!\n", timeout);
511     status = errno;
512   }
513
514   alarm(0);
515
516   fprintf(stderr, "DEBUG: lpd_command returning %d\n", status);
517
518   return (status);
519 }
520
521
522 /*
523  * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol.
524  */
525
526 static int                              /* O - Zero on success, non-zero on failure */
527 lpd_queue(const char *hostname,         /* I - Host to connect to */
528           int        port,              /* I - Port to connect on */
529           const char *printer,          /* I - Printer/queue name */
530           const char *filename,         /* I - File to print */
531           const char *user,             /* I - Requesting user */
532           const char *title,            /* I - Job title */
533           int        copies,            /* I - Number of copies */
534           int        banner,            /* I - Print LPD banner? */
535           int        format,            /* I - Format specifier */
536           int        order,             /* I - Order of data/control files */
537           int        reserve,           /* I - Reserve ports? */
538           int        manual_copies,     /* I - Do copies by hand... */
539           int        timeout)           /* I - Timeout... */
540 {
541   FILE                  *fp;            /* Job file */
542   char                  localhost[255]; /* Local host name */
543   int                   error;          /* Error number */
544   struct stat           filestats;      /* File statistics */
545   int                   lport;          /* LPD connection local port */
546   int                   fd;             /* LPD socket */
547   char                  control[10240], /* LPD control 'file' */
548                         *cptr;          /* Pointer into control file string */
549   char                  status;         /* Status byte from command */
550   char                  portname[255];  /* Port name */
551   http_addrlist_t       *addrlist,      /* Address list */
552                         *addr;          /* Socket address */
553   int                   copy;           /* Copies written */
554   size_t                nbytes;         /* Number of bytes written */
555   off_t                 tbytes;         /* Total bytes written */
556   char                  buffer[65536];  /* Output buffer */
557 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
558   struct sigaction      action;         /* Actions for POSIX signals */
559 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
560
561
562  /*
563   * Setup an alarm handler for timeouts...
564   */
565
566 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
567   sigset(SIGALRM, lpd_timeout);
568 #elif defined(HAVE_SIGACTION)
569   memset(&action, 0, sizeof(action));
570
571   sigemptyset(&action.sa_mask);
572   action.sa_handler = lpd_timeout;
573   sigaction(SIGALRM, &action, NULL);
574 #else
575   signal(SIGALRM, lpd_timeout);
576 #endif /* HAVE_SIGSET */
577
578  /*
579   * Find the printer...
580   */
581
582   sprintf(portname, "%d", port);
583
584   if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
585   {
586     fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n",
587             hostname);
588     return (CUPS_BACKEND_STOP);
589   }
590
591  /*
592   * Loop forever trying to print the file...
593   */
594
595   while (!abort_job)
596   {
597    /*
598     * First try to reserve a port for this connection...
599     */
600
601     fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n",
602             hostname, printer);
603
604     for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist;;
605          addr = addr->next)
606     {
607      /*
608       * Stop if this job has been cancelled...
609       */
610
611       if (abort_job)
612       {
613         httpAddrFreeList(addrlist);
614
615         return (CUPS_BACKEND_FAILED);
616       }
617
618      /*
619       * Choose the next priviledged port...
620       */
621
622       if (!addr)
623         addr = addrlist;
624
625       lport --;
626
627       if (lport < 721 && reserve == RESERVE_RFC1179)
628         lport = 731;
629       else if (lport < 1)
630         lport = 1023;
631
632 #ifdef HAVE_GETEUID
633       if (geteuid() || !reserve)
634 #else
635       if (getuid() || !reserve)
636 #endif /* HAVE_GETEUID */
637       {
638        /*
639         * Just create a regular socket...
640         */
641
642         if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0)
643         {
644           perror("ERROR: Unable to create socket");
645           sleep(1);
646
647           continue;
648         }
649
650         lport = 0;
651       }
652       else
653       {
654        /*
655         * We're running as root and want to comply with RFC 1179.  Reserve a
656         * priviledged lport between 721 and 731...
657         */
658
659         if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0)
660         {
661           perror("ERROR: Unable to reserve port");
662           sleep(1);
663
664           continue;
665         }
666       }
667
668      /*
669       * Connect to the printer or server...
670       */
671
672       if (abort_job)
673       {
674         httpAddrFreeList(addrlist);
675
676         close(fd);
677
678         return (CUPS_BACKEND_FAILED);
679       }
680
681       if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr))))
682         break;
683
684       error = errno;
685       close(fd);
686       fd = -1;
687
688       if (addr->next)
689         continue;
690
691       if (getenv("CLASS") != NULL)
692       {
693        /*
694         * If the CLASS environment variable is set, the job was submitted
695         * to a class and not to a specific queue.  In this case, we want
696         * to abort immediately so that the job can be requeued on the next
697         * available printer in the class.
698         */
699
700         fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n",
701                 hostname);
702
703         httpAddrFreeList(addrlist);
704
705        /*
706         * Sleep 5 seconds to keep the job from requeuing too rapidly...
707         */
708
709         sleep(5);
710
711         return (CUPS_BACKEND_FAILED);
712       }
713
714       if (error == ECONNREFUSED || error == EHOSTDOWN ||
715           error == EHOSTUNREACH)
716       {
717         fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n",
718                 hostname);
719         sleep(30);
720       }
721       else if (error == EADDRINUSE)
722       {
723        /*
724         * Try on another port...
725         */
726
727         sleep(1);
728       }
729       else
730       {
731         perror("ERROR: Unable to connect to printer; will retry in 30 seconds...");
732         sleep(30);
733       }
734     }
735
736     fprintf(stderr, "INFO: Connected to %s...\n", hostname);
737     fprintf(stderr, "DEBUG: Connected on ports %d (local %d)...\n", port,
738             lport);
739
740    /*
741     * Next, open the print file and figure out its size...
742     */
743
744     if (stat(filename, &filestats))
745     {
746       httpAddrFreeList(addrlist);
747       close(fd);
748
749       perror("ERROR: unable to stat print file");
750       return (CUPS_BACKEND_FAILED);
751     }
752
753     filestats.st_size *= manual_copies;
754
755     if ((fp = fopen(filename, "rb")) == NULL)
756     {
757       httpAddrFreeList(addrlist);
758       close(fd);
759
760       perror("ERROR: unable to open print file for reading");
761       return (CUPS_BACKEND_FAILED);
762     }
763
764    /*
765     * Send a job header to the printer, specifying no banner page and
766     * literal output...
767     */
768
769     if (lpd_command(fd, timeout, "\002%s\n",
770                     printer))           /* Receive print job(s) */
771     {
772       httpAddrFreeList(addrlist);
773       close(fd);
774       return (CUPS_BACKEND_FAILED);
775     }
776
777     httpGetHostname(localhost, sizeof(localhost));
778
779     snprintf(control, sizeof(control),
780              "H%.31s\n"         /* RFC 1179, Section 7.2 - host name <= 31 chars */
781              "P%.31s\n"         /* RFC 1179, Section 7.2 - user name <= 31 chars */
782              "J%.99s\n",        /* RFC 1179, Section 7.2 - job name <= 99 chars */
783              localhost, user, title);
784     cptr = control + strlen(control);
785
786     if (banner)
787     {
788       snprintf(cptr, sizeof(control) - (cptr - control),
789                "C%.31s\n"       /* RFC 1179, Section 7.2 - class name <= 31 chars */
790                "L%s\n",
791                localhost, user);
792       cptr   += strlen(cptr);
793     }
794
795     while (copies > 0)
796     {
797       snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n",
798                format, (int)getpid() % 1000, localhost);
799       cptr   += strlen(cptr);
800       copies --;
801     }
802
803     snprintf(cptr, sizeof(control) - (cptr - control),
804              "UdfA%03d%.15s\n"
805              "N%.131s\n",       /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */
806              (int)getpid() % 1000, localhost, title);
807
808     fprintf(stderr, "DEBUG: Control file is:\n%s", control);
809
810     if (order == ORDER_CONTROL_DATA)
811     {
812       if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
813                       (int)getpid() % 1000, localhost))
814       {
815         httpAddrFreeList(addrlist);
816         close(fd);
817
818         return (CUPS_BACKEND_FAILED);
819       }
820
821       fprintf(stderr, "INFO: Sending control file (%u bytes)\n",
822               (unsigned)strlen(control));
823
824       if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
825       {
826         status = errno;
827         perror("ERROR: Unable to write control file");
828       }
829       else
830       {
831         alarm(timeout);
832
833         if (read(fd, &status, 1) < 1)
834         {
835           fprintf(stderr, "WARNING: Remote host did not respond with control "
836                           "status byte after %d seconds!\n", timeout);
837           status = errno;
838         }
839
840         alarm(0);
841       }
842
843       if (status != 0)
844         fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
845                 status);
846       else
847         fputs("INFO: Control file sent successfully\n", stderr);
848     }
849     else
850       status = 0;
851
852     if (status == 0)
853     {
854      /*
855       * Send the print file...
856       */
857
858       if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n",
859                       CUPS_LLCAST filestats.st_size, (int)getpid() % 1000,
860                       localhost))
861       {
862         httpAddrFreeList(addrlist);
863         close(fd);
864
865         return (CUPS_BACKEND_FAILED);
866       }
867
868       fprintf(stderr, "INFO: Sending data file (" CUPS_LLFMT " bytes)\n",
869               CUPS_LLCAST filestats.st_size);
870
871       tbytes = 0;
872       for (copy = 0; copy < manual_copies; copy ++)
873       {
874         rewind(fp);
875
876         while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
877         {
878           fprintf(stderr, "INFO: Spooling LPR job, %.0f%% complete...\n",
879                   100.0 * tbytes / filestats.st_size);
880
881           if (lpd_write(fd, buffer, nbytes) < nbytes)
882           {
883             perror("ERROR: Unable to send print file to printer");
884             break;
885           }
886           else
887             tbytes += nbytes;
888         }
889       }
890
891       if (tbytes < filestats.st_size)
892         status = errno;
893       else if (lpd_write(fd, "", 1) < 1)
894       {
895         perror("ERROR: Unable to send trailing nul to printer");
896         status = errno;
897       }
898       else
899       {
900        /*
901         * Read the status byte from the printer; if we can't read the byte
902         * back now, we should set status to "errno", however at this point
903         * we know the printer got the whole file and we don't necessarily
904         * want to requeue it over and over...
905         */
906
907         alarm(timeout);
908
909         if (recv(fd, &status, 1, 0) < 1)
910         {
911           fprintf(stderr, "WARNING: Remote host did not respond with data "
912                           "status byte after %d seconds!\n", timeout);
913           status = 0;
914         }
915
916         alarm(0);
917       }
918
919       if (status != 0)
920         fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n",
921                 status);
922       else
923         fputs("INFO: Data file sent successfully\n", stderr);
924     }
925
926     if (status == 0 && order == ORDER_DATA_CONTROL)
927     {
928       if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control),
929                       (int)getpid() % 1000, localhost))
930       {
931         httpAddrFreeList(addrlist);
932         close(fd);
933
934         return (CUPS_BACKEND_FAILED);
935       }
936
937       fprintf(stderr, "INFO: Sending control file (%lu bytes)\n",
938               (unsigned long)strlen(control));
939
940       if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1))
941       {
942         status = errno;
943         perror("ERROR: Unable to write control file");
944       }
945       else
946       {
947         alarm(timeout);
948
949         if (read(fd, &status, 1) < 1)
950         {
951           fprintf(stderr, "WARNING: Remote host did not respond with control "
952                           "status byte after %d seconds!\n", timeout);
953           status = errno;
954         }
955
956         alarm(0);
957       }
958
959       if (status != 0)
960         fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n",
961                 status);
962       else
963         fputs("INFO: Control file sent successfully\n", stderr);
964     }
965
966    /*
967     * Close the socket connection and input file...
968     */
969
970     close(fd);
971     fclose(fp);
972
973     if (status == 0)
974     {
975       httpAddrFreeList(addrlist);
976
977       return (CUPS_BACKEND_OK);
978     }
979
980    /*
981     * Waiting for a retry...
982     */
983
984     sleep(30);
985   }
986
987   httpAddrFreeList(addrlist);
988
989  /*
990   * If we get here, then the job has been cancelled...
991   */
992
993   return (CUPS_BACKEND_FAILED);
994 }
995
996
997 /*
998  * 'lpd_timeout()' - Handle timeout alarms...
999  */
1000
1001 static void
1002 lpd_timeout(int sig)                    /* I - Signal number */
1003 {
1004   (void)sig;
1005
1006 #if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION)
1007   signal(SIGALRM, lpd_timeout);
1008 #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */
1009 }
1010
1011
1012 /*
1013  * 'lpd_write()' - Write a buffer of data to an LPD server.
1014  */
1015
1016 static int                              /* O - Number of bytes written or -1 on error */
1017 lpd_write(int  lpd_fd,                  /* I - LPD socket */
1018           char *buffer,                 /* I - Buffer to write */
1019           int  length)                  /* I - Number of bytes to write */
1020 {
1021   int   bytes,                          /* Number of bytes written */
1022         total;                          /* Total number of bytes written */
1023
1024
1025   if (abort_job)
1026     return (-1);
1027
1028   total = 0;
1029   while ((bytes = send(lpd_fd, buffer, length - total, 0)) >= 0)
1030   {
1031     total  += bytes;
1032     buffer += bytes;
1033
1034     if (total == length)
1035       break;
1036   }
1037
1038   if (bytes < 0)
1039     return (-1);
1040   else
1041     return (length);
1042 }
1043
1044
1045 #ifndef HAVE_RRESVPORT_AF
1046 /*
1047  * 'rresvport_af()' - A simple implementation of rresvport_af().
1048  */
1049
1050 static int                              /* O  - Socket or -1 on error */
1051 rresvport_af(int *port,                 /* IO - Port number to bind to */
1052              int family)                /* I  - Address family */
1053 {
1054   http_addr_t   addr;                   /* Socket address */
1055   int           fd;                     /* Socket file descriptor */
1056
1057
1058  /*
1059   * Try to create an IPv4 socket...
1060   */
1061
1062   if ((fd = socket(family, SOCK_STREAM, 0)) < 0)
1063     return (-1);
1064
1065  /*
1066   * Initialize the address buffer...
1067   */
1068
1069   memset(&addr, 0, sizeof(addr));
1070   addr.addr.sa_family = family;
1071
1072  /*
1073   * Try to bind the socket to a reserved port...
1074   */
1075
1076   while (*port > 511)
1077   {
1078    /*
1079     * Set the port number...
1080     */
1081
1082 #  ifdef AF_INET6
1083     if (family == AF_INET6)
1084       addr.ipv6.sin6_port = htons(*port);
1085     else
1086 #  endif /* AF_INET6 */
1087     addr.ipv4.sin_port = htons(*port);
1088
1089    /*
1090     * Try binding the port to the socket; return if all is OK...
1091     */
1092
1093     if (!bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
1094       return (fd);
1095
1096    /*
1097     * Stop if we have any error other than "address already in use"...
1098     */
1099
1100     if (errno != EADDRINUSE)
1101     {
1102 #  ifdef WIN32
1103       closesocket(fd);
1104 #  else
1105       close(fd);
1106 #  endif /* WIN32 */
1107
1108       return (-1);
1109     }
1110
1111    /*
1112     * Try the next port...
1113     */
1114
1115     (*port)--;
1116   }
1117
1118  /*
1119   * Wasn't able to bind to a reserved port, so close the socket and return
1120   * -1...
1121   */
1122
1123 #  ifdef WIN32
1124   closesocket(fd);
1125 #  else
1126   close(fd);
1127 #  endif /* WIN32 */
1128
1129   return (-1);
1130 }
1131 #endif /* !HAVE_RRESVPORT_AF */
1132
1133
1134 /*
1135  * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1136  */
1137
1138 static void
1139 sigterm_handler(int sig)                /* I - Signal */
1140 {
1141   (void)sig;    /* remove compiler warnings... */
1142
1143   abort_job = 1;
1144 }
1145
1146
1147 /*
1148  * End of "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $".
1149  */