]> git.pld-linux.org Git - packages/cups.git/blob - add-ipp-backend-of-cups-1.4.patch
- rel 2; add ipp14 backend; fixes for ipp15 backend; other fixes - everything from...
[packages/cups.git] / add-ipp-backend-of-cups-1.4.patch
1 --- a/backend/Makefile
2 +++ b/backend/Makefile
3 @@ -21,12 +21,12 @@
4  # Object files...
5  #
6  
7 -RBACKENDS =    ipp lpd $(DNSSD_BACKEND)
8 +RBACKENDS =    ipp ipp14 lpd $(DNSSD_BACKEND)
9  UBACKENDS =    $(LEGACY_BACKENDS) serial snmp socket usb
10  UNITTESTS =    test1284 testbackend testsupplies
11  TARGETS =      libbackend.a $(RBACKENDS) $(UBACKENDS)
12  LIBOBJS        =       ieee1284.o network.o runloop.o snmp-supplies.o
13 -OBJS   =       ipp.o lpd.o dnssd.o parallel.o serial.o snmp.o \
14 +OBJS   =       ipp.o ipp14.o lpd.o dnssd.o parallel.o serial.o snmp.o \
15                 socket.o test1284.o testbackend.o testsupplies.o usb.o
16  
17  
18 @@ -218,6 +218,17 @@
19  
20  
21  #
22 +# ipp14
23 +#
24 +
25 +ipp14: ipp14.o ../cups/$(LIBCUPS) libbackend.a
26 +       echo Linking $@...
27 +       $(CC) $(LDFLAGS) -o ipp14 ipp14.o libbackend.a $(LIBS)
28 +       #$(RM) http
29 +       #$(LN) ipp14 http
30 +
31 +
32 +#
33  # lpd
34  #
35  
36 --- /dev/null
37 +++ b/backend/ipp14.c
38 @@ -0,0 +1,1953 @@
39 +/*
40 + * "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $"
41 + *
42 + *   IPP backend for the Common UNIX Printing System (CUPS).
43 + *
44 + *   Copyright 2007-2010 by Apple Inc.
45 + *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
46 + *
47 + *   These coded instructions, statements, and computer programs are the
48 + *   property of Apple Inc. and are protected by Federal copyright
49 + *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
50 + *   "LICENSE" which should have been included with this file.  If this
51 + *   file is missing or damaged, see the license at "http://www.cups.org/".
52 + *
53 + *   This file is subject to the Apple OS-Developed Software exception.
54 + *
55 + * Contents:
56 + *
57 + *   main()                 - Send a file to the printer or server.
58 + *   cancel_job()           - Cancel a print job.
59 + *   check_printer_state()  - Check the printer state...
60 + *   compress_files()       - Compress print files...
61 + *   password_cb()          - Disable the password prompt for
62 + *                            cupsDoFileRequest().
63 + *   report_attr()          - Report an IPP attribute value.
64 + *   report_printer_state() - Report the printer state.
65 + *   run_pictwps_filter()   - Convert PICT files to PostScript when printing
66 + *                            remotely.
67 + *   sigterm_handler()      - Handle 'terminate' signals that stop the backend.
68 + */
69 +
70 +/*
71 + * Include necessary headers.
72 + */
73 +
74 +#include <cups/http-private.h>
75 +#include "backend-private.h"
76 +#include <sys/types.h>
77 +#include <sys/stat.h>
78 +#include <sys/wait.h>
79 +
80 +/*
81 + * Globals...
82 + */
83 +
84 +static char    *password = NULL;       /* Password for device URI */
85 +static int     password_tries = 0;     /* Password tries */
86 +static const char *auth_info_required = "none";
87 +                                       /* New auth-info-required value */
88 +#ifdef __APPLE__
89 +static char    pstmpname[1024] = "";   /* Temporary PostScript file name */
90 +#endif /* __APPLE__ */
91 +static char    tmpfilename[1024] = ""; /* Temporary spool file name */
92 +static int     job_cancelled = 0;      /* Job cancelled? */
93 +
94 +
95 +/*
96 + * Local functions...
97 + */
98 +
99 +static void    cancel_job(http_t *http, const char *uri, int id,
100 +                          const char *resource, const char *user, int version);
101 +static void    check_printer_state(http_t *http, const char *uri,
102 +                                   const char *resource, const char *user,
103 +                                   int version, int job_id);
104 +#ifdef HAVE_LIBZ
105 +static void    compress_files(int num_files, char **files);
106 +#endif /* HAVE_LIBZ */
107 +static const char *password_cb(const char *);
108 +static void    report_attr(ipp_attribute_t *attr);
109 +static int     report_printer_state(ipp_t *ipp, int job_id);
110 +
111 +#ifdef __APPLE__
112 +static int     run_pictwps_filter(char **argv, const char *filename);
113 +#endif /* __APPLE__ */
114 +static void    sigterm_handler(int sig);
115 +
116 +
117 +/*
118 + * 'main()' - Send a file to the printer or server.
119 + *
120 + * Usage:
121 + *
122 + *    printer-uri job-id user title copies options [file]
123 + */
124 +
125 +int                                    /* O - Exit status */
126 +main(int  argc,                                /* I - Number of command-line args */
127 +     char *argv[])                     /* I - Command-line arguments */
128 +{
129 +  int          i;                      /* Looping var */
130 +  int          send_options;           /* Send job options? */
131 +  int          num_options;            /* Number of printer options */
132 +  cups_option_t        *options;               /* Printer options */
133 +  const char   *device_uri;            /* Device URI */
134 +  char         scheme[255],            /* Scheme in URI */
135 +               hostname[1024],         /* Hostname */
136 +               username[255],          /* Username info */
137 +               resource[1024],         /* Resource info (printer name) */
138 +               addrname[256],          /* Address name */
139 +               *optptr,                /* Pointer to URI options */
140 +               *name,                  /* Name of option */
141 +               *value,                 /* Value of option */
142 +               sep;                    /* Separator character */
143 +  int          snmp_fd,                /* SNMP socket */
144 +               start_count,            /* Page count via SNMP at start */
145 +               page_count,             /* Page count via SNMP */
146 +               have_supplies;          /* Printer supports supply levels? */
147 +  int          num_files;              /* Number of files to print */
148 +  char         **files,                /* Files to print */
149 +               *filename;              /* Pointer to single filename */
150 +  int          port;                   /* Port number (not used) */
151 +  char         uri[HTTP_MAX_URI];      /* Updated URI without user/pass */
152 +  ipp_status_t ipp_status;             /* Status of IPP request */
153 +  http_t       *http;                  /* HTTP connection */
154 +  ipp_t                *request,               /* IPP request */
155 +               *response,              /* IPP response */
156 +               *supported;             /* get-printer-attributes response */
157 +  time_t       start_time;             /* Time of first connect */
158 +  int          recoverable;            /* Recoverable error shown? */
159 +  int          contimeout;             /* Connection timeout */
160 +  int          delay;                  /* Delay for retries... */
161 +  int          compression,            /* Do compression of the job data? */
162 +               waitjob,                /* Wait for job complete? */
163 +               waitprinter;            /* Wait for printer ready? */
164 +  ipp_attribute_t *job_id_attr;                /* job-id attribute */
165 +  int          job_id;                 /* job-id value */
166 +  ipp_attribute_t *job_sheets;         /* job-media-sheets-completed */
167 +  ipp_attribute_t *job_state;          /* job-state */
168 +  ipp_attribute_t *copies_sup;         /* copies-supported */
169 +  ipp_attribute_t *format_sup;         /* document-format-supported */
170 +  ipp_attribute_t *printer_state;      /* printer-state attribute */
171 +  ipp_attribute_t *printer_accepting;  /* printer-is-accepting-jobs */
172 +  int          copies,                 /* Number of copies for job */
173 +               copies_remaining;       /* Number of copies remaining */
174 +  const char   *content_type,          /* CONTENT_TYPE environment variable */
175 +               *final_content_type;    /* FINAL_CONTENT_TYPE environment var */
176 +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
177 +  struct sigaction action;             /* Actions for POSIX signals */
178 +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
179 +  int          version;                /* IPP version */
180 +  static const char * const pattrs[] =
181 +               {                       /* Printer attributes we want */
182 +                  "com.apple.print.recoverable-message",
183 +                 "copies-supported",
184 +                 "document-format-supported",
185 +                 "marker-colors",
186 +                 "marker-high-levels",
187 +                 "marker-levels",
188 +                 "marker-low-levels",
189 +                 "marker-message",
190 +                 "marker-names",
191 +                 "marker-types",
192 +                 "printer-is-accepting-jobs",
193 +                 "printer-state",
194 +                 "printer-state-message",
195 +                 "printer-state-reasons",
196 +               };
197 +  static const char * const jattrs[] =
198 +               {                       /* Job attributes we want */
199 +                 "job-media-sheets-completed",
200 +                 "job-state"
201 +               };
202 +
203 +
204 + /*
205 +  * Make sure status messages are not buffered...
206 +  */
207 +
208 +  setbuf(stderr, NULL);
209 +
210 + /*
211 +  * Ignore SIGPIPE and catch SIGTERM signals...
212 +  */
213 +
214 +#ifdef HAVE_SIGSET
215 +  sigset(SIGPIPE, SIG_IGN);
216 +  sigset(SIGTERM, sigterm_handler);
217 +#elif defined(HAVE_SIGACTION)
218 +  memset(&action, 0, sizeof(action));
219 +  action.sa_handler = SIG_IGN;
220 +  sigaction(SIGPIPE, &action, NULL);
221 +
222 +  sigemptyset(&action.sa_mask);
223 +  sigaddset(&action.sa_mask, SIGTERM);
224 +  action.sa_handler = sigterm_handler;
225 +  sigaction(SIGTERM, &action, NULL);
226 +#else
227 +  signal(SIGPIPE, SIG_IGN);
228 +  signal(SIGTERM, sigterm_handler);
229 +#endif /* HAVE_SIGSET */
230 +
231 + /*
232 +  * Check command-line...
233 +  */
234 +
235 +  if (argc == 1)
236 +  {
237 +    char *s;
238 +
239 +    if ((s = strrchr(argv[0], '/')) != NULL)
240 +      s ++;
241 +    else
242 +      s = argv[0];
243 +
244 +    printf("network %s \"Unknown\" \"%s (%s)\"\n",
245 +           s, _cupsLangString(cupsLangDefault(),
246 +                             _("Internet Printing Protocol")), s);
247 +    return (CUPS_BACKEND_OK);
248 +  }
249 +  else if (argc < 6)
250 +  {
251 +    _cupsLangPrintf(stderr,
252 +                    _("Usage: %s job-id user title copies options [file]\n"),
253 +                   argv[0]);
254 +    return (CUPS_BACKEND_STOP);
255 +  }
256 +
257 + /*
258 +  * Get the (final) content type...
259 +  */
260 +
261 +  if ((content_type = getenv("CONTENT_TYPE")) == NULL)
262 +    content_type = "application/octet-stream";
263 +
264 +  if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
265 +  {
266 +    final_content_type = content_type;
267 +
268 +    if (!strncmp(final_content_type, "printer/", 8))
269 +      final_content_type = "application/vnd.cups-raw";
270 +  }
271 +
272 + /*
273 +  * Extract the hostname and printer name from the URI...
274 +  */
275 +
276 +  if ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
277 +    return (CUPS_BACKEND_FAILED);
278 +
279 +  httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
280 +                  username, sizeof(username), hostname, sizeof(hostname), &port,
281 +                 resource, sizeof(resource));
282 +
283 +  if (!port)
284 +    port = IPP_PORT;                   /* Default to port 631 */
285 +
286 +  if (!strcmp(scheme, "https"))
287 +    cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
288 +  else
289 +    cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
290 +
291 + /*
292 +  * See if there are any options...
293 +  */
294 +
295 +  compression = 0;
296 +  version     = 11;
297 +  waitjob     = 1;
298 +  waitprinter = 1;
299 +  contimeout  = 7 * 24 * 60 * 60;
300 +
301 +  if ((optptr = strchr(resource, '?')) != NULL)
302 +  {
303 +   /*
304 +    * Yup, terminate the device name string and move to the first
305 +    * character of the optptr...
306 +    */
307 +
308 +    *optptr++ = '\0';
309 +
310 +   /*
311 +    * Then parse the optptr...
312 +    */
313 +
314 +    while (*optptr)
315 +    {
316 +     /*
317 +      * Get the name...
318 +      */
319 +
320 +      name = optptr;
321 +
322 +      while (*optptr && *optptr != '=' && *optptr != '+' && *optptr != '&')
323 +        optptr ++;
324 +
325 +      if ((sep = *optptr) != '\0')
326 +        *optptr++ = '\0';
327 +
328 +      if (sep == '=')
329 +      {
330 +       /*
331 +        * Get the value...
332 +       */
333 +
334 +        value = optptr;
335 +
336 +       while (*optptr && *optptr != '+' && *optptr != '&')
337 +         optptr ++;
338 +
339 +        if (*optptr)
340 +         *optptr++ = '\0';
341 +      }
342 +      else
343 +        value = (char *)"";
344 +
345 +     /*
346 +      * Process the option...
347 +      */
348 +
349 +      if (!strcasecmp(name, "waitjob"))
350 +      {
351 +       /*
352 +        * Wait for job completion?
353 +       */
354 +
355 +        waitjob = !strcasecmp(value, "on") ||
356 +                 !strcasecmp(value, "yes") ||
357 +                 !strcasecmp(value, "true");
358 +      }
359 +      else if (!strcasecmp(name, "waitprinter"))
360 +      {
361 +       /*
362 +        * Wait for printer idle?
363 +       */
364 +
365 +        waitprinter = !strcasecmp(value, "on") ||
366 +                     !strcasecmp(value, "yes") ||
367 +                     !strcasecmp(value, "true");
368 +      }
369 +      else if (!strcasecmp(name, "encryption"))
370 +      {
371 +       /*
372 +        * Enable/disable encryption?
373 +       */
374 +
375 +        if (!strcasecmp(value, "always"))
376 +         cupsSetEncryption(HTTP_ENCRYPT_ALWAYS);
377 +        else if (!strcasecmp(value, "required"))
378 +         cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
379 +        else if (!strcasecmp(value, "never"))
380 +         cupsSetEncryption(HTTP_ENCRYPT_NEVER);
381 +        else if (!strcasecmp(value, "ifrequested"))
382 +         cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED);
383 +       else
384 +       {
385 +         _cupsLangPrintf(stderr,
386 +                         _("ERROR: Unknown encryption option value \"%s\"!\n"),
387 +                         value);
388 +        }
389 +      }
390 +      else if (!strcasecmp(name, "version"))
391 +      {
392 +        if (!strcmp(value, "1.0"))
393 +         version = 10;
394 +       else if (!strcmp(value, "1.1"))
395 +         version = 11;
396 +       else if (!strcmp(value, "2.0"))
397 +         version = 20;
398 +       else if (!strcmp(value, "2.1"))
399 +         version = 21;
400 +       else
401 +       {
402 +         _cupsLangPrintf(stderr,
403 +                         _("ERROR: Unknown version option value \"%s\"!\n"),
404 +                         value);
405 +       }
406 +      }
407 +#ifdef HAVE_LIBZ
408 +      else if (!strcasecmp(name, "compression"))
409 +      {
410 +        compression = !strcasecmp(value, "true") ||
411 +                     !strcasecmp(value, "yes") ||
412 +                     !strcasecmp(value, "on") ||
413 +                     !strcasecmp(value, "gzip");
414 +      }
415 +#endif /* HAVE_LIBZ */
416 +      else if (!strcasecmp(name, "contimeout"))
417 +      {
418 +       /*
419 +        * Set the connection timeout...
420 +       */
421 +
422 +       if (atoi(value) > 0)
423 +         contimeout = atoi(value);
424 +      }
425 +      else
426 +      {
427 +       /*
428 +        * Unknown option...
429 +       */
430 +
431 +       _cupsLangPrintf(stderr,
432 +                       _("ERROR: Unknown option \"%s\" with value \"%s\"!\n"),
433 +                       name, value);
434 +      }
435 +    }
436 +  }
437 +
438 + /*
439 +  * If we have 7 arguments, print the file named on the command-line.
440 +  * Otherwise, copy stdin to a temporary file and print the temporary
441 +  * file.
442 +  */
443 +
444 +  if (argc == 6)
445 +  {
446 +   /*
447 +    * Copy stdin to a temporary file...
448 +    */
449 +
450 +    int                        fd;             /* File descriptor */
451 +    http_addrlist_t    *addrlist;      /* Address list */
452 +    off_t              tbytes;         /* Total bytes copied */
453 +
454 +
455 +    fputs("STATE: +connecting-to-device\n", stderr);
456 +    fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
457 +
458 +    if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, "1")) == NULL)
459 +    {
460 +      _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
461 +                     hostname);
462 +      return (CUPS_BACKEND_STOP);
463 +    }
464 +
465 +    snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family);
466 +
467 +    if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0)
468 +    {
469 +      _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
470 +      return (CUPS_BACKEND_FAILED);
471 +    }
472 +
473 +    _cupsLangPuts(stderr, _("INFO: Copying print data...\n"));
474 +
475 +    tbytes = backendRunLoop(-1, fd, snmp_fd, &(addrlist->addr), 0, 0,
476 +                            backendNetworkSideCB);
477 +
478 +    if (snmp_fd >= 0)
479 +      _cupsSNMPClose(snmp_fd);
480 +
481 +    httpAddrFreeList(addrlist);
482 +
483 +    close(fd);
484 +
485 +   /*
486 +    * Don't try printing files less than 2 bytes...
487 +    */
488 +
489 +    if (tbytes <= 1)
490 +    {
491 +      _cupsLangPuts(stderr, _("ERROR: Empty print file!\n"));
492 +      unlink(tmpfilename);
493 +      return (CUPS_BACKEND_FAILED);
494 +    }
495 +
496 +   /*
497 +    * Point to the single file from stdin...
498 +    */
499 +
500 +    filename     = tmpfilename;
501 +    num_files    = 1;
502 +    files        = &filename;
503 +    send_options = 0;
504 +  }
505 +  else
506 +  {
507 +   /*
508 +    * Point to the files on the command-line...
509 +    */
510 +
511 +    num_files    = argc - 6;
512 +    files        = argv + 6;
513 +    send_options = 1;
514 +
515 +#ifdef HAVE_LIBZ
516 +    if (compression)
517 +      compress_files(num_files, files);
518 +#endif /* HAVE_LIBZ */
519 +  }
520 +
521 +  fprintf(stderr, "DEBUG: %d files to send in job...\n", num_files);
522 +
523 + /*
524 +  * Set the authentication info, if any...
525 +  */
526 +
527 +  cupsSetPasswordCB(password_cb);
528 +
529 +  if (username[0])
530 +  {
531 +   /*
532 +    * Use authenticaion information in the device URI...
533 +    */
534 +
535 +    if ((password = strchr(username, ':')) != NULL)
536 +      *password++ = '\0';
537 +
538 +    cupsSetUser(username);
539 +  }
540 +  else if (!getuid())
541 +  {
542 +   /*
543 +    * Try loading authentication information from the environment.
544 +    */
545 +
546 +    const char *ptr = getenv("AUTH_USERNAME");
547 +
548 +    if (ptr)
549 +      cupsSetUser(ptr);
550 +
551 +    password = getenv("AUTH_PASSWORD");
552 +  }
553 +
554 + /*
555 +  * Try connecting to the remote server...
556 +  */
557 +
558 +  delay       = 5;
559 +  recoverable = 0;
560 +  start_time  = time(NULL);
561 +
562 +  fputs("STATE: +connecting-to-device\n", stderr);
563 +
564 +  do
565 +  {
566 +    fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
567 +    _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n"));
568 +
569 +    if ((http = httpConnectEncrypt(hostname, port, cupsEncryption())) == NULL)
570 +    {
571 +      if (job_cancelled)
572 +       break;
573 +
574 +      if (getenv("CLASS") != NULL)
575 +      {
576 +       /*
577 +        * If the CLASS environment variable is set, the job was submitted
578 +       * to a class and not to a specific queue.  In this case, we want
579 +       * to abort immediately so that the job can be requeued on the next
580 +       * available printer in the class.
581 +       */
582 +
583 +        _cupsLangPuts(stderr,
584 +                     _("INFO: Unable to contact printer, queuing on next "
585 +                       "printer in class...\n"));
586 +
587 +        if (tmpfilename[0])
588 +         unlink(tmpfilename);
589 +
590 +       /*
591 +        * Sleep 5 seconds to keep the job from requeuing too rapidly...
592 +       */
593 +
594 +       sleep(5);
595 +
596 +        return (CUPS_BACKEND_FAILED);
597 +      }
598 +
599 +      if (errno == ECONNREFUSED || errno == EHOSTDOWN ||
600 +          errno == EHOSTUNREACH)
601 +      {
602 +        if (contimeout && (time(NULL) - start_time) > contimeout)
603 +       {
604 +         _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
605 +         return (CUPS_BACKEND_FAILED);
606 +       }
607 +
608 +        recoverable = 1;
609 +
610 +       _cupsLangPrintf(stderr,
611 +                       _("WARNING: recoverable: Network host \'%s\' is busy; "
612 +                         "will retry in %d seconds...\n"),
613 +                       hostname, delay);
614 +
615 +       sleep(delay);
616 +
617 +       if (delay < 30)
618 +         delay += 5;
619 +      }
620 +      else if (h_errno)
621 +      {
622 +       _cupsLangPrintf(stderr, _("ERROR: Unable to locate printer \'%s\'!\n"),
623 +                       hostname);
624 +       return (CUPS_BACKEND_STOP);
625 +      }
626 +      else
627 +      {
628 +        recoverable = 1;
629 +
630 +        fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno));
631 +       _cupsLangPuts(stderr,
632 +                     _("ERROR: recoverable: Unable to connect to printer; will "
633 +                       "retry in 30 seconds...\n"));
634 +       sleep(30);
635 +      }
636 +
637 +      if (job_cancelled)
638 +       break;
639 +    }
640 +  }
641 +  while (http == NULL);
642 +
643 +  if (job_cancelled || !http)
644 +  {
645 +    if (tmpfilename[0])
646 +      unlink(tmpfilename);
647 +
648 +    return (CUPS_BACKEND_FAILED);
649 +  }
650 +
651 +  fputs("STATE: -connecting-to-device\n", stderr);
652 +  _cupsLangPuts(stderr, _("INFO: Connected to printer...\n"));
653 +
654 +#ifdef AF_INET6
655 +  if (http->hostaddr->addr.sa_family == AF_INET6)
656 +    fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n",
657 +           httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
658 +           ntohs(http->hostaddr->ipv6.sin6_port));
659 +  else
660 +#endif /* AF_INET6 */
661 +    if (http->hostaddr->addr.sa_family == AF_INET)
662 +      fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n",
663 +             httpAddrString(http->hostaddr, addrname, sizeof(addrname)),
664 +             ntohs(http->hostaddr->ipv4.sin_port));
665 +
666 + /*
667 +  * See if the printer supports SNMP...
668 +  */
669 +
670 +  if ((snmp_fd = _cupsSNMPOpen(http->hostaddr->addr.sa_family)) >= 0)
671 +    have_supplies = !backendSNMPSupplies(snmp_fd, http->hostaddr, &start_count,
672 +                                         NULL);
673 +  else
674 +    have_supplies = start_count = 0;
675 +
676 + /*
677 +  * Build a URI for the printer and fill the standard IPP attributes for
678 +  * an IPP_PRINT_FILE request.  We can't use the URI in argv[0] because it
679 +  * might contain username:password information...
680 +  */
681 +
682 +  httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, hostname,
683 +                 port, resource);
684 +
685 + /*
686 +  * First validate the destination and see if the device supports multiple
687 +  * copies.  We have to do this because some IPP servers (e.g. HP JetDirect)
688 +  * don't support the copies attribute...
689 +  */
690 +
691 +  copies_sup = NULL;
692 +  format_sup = NULL;
693 +  supported  = NULL;
694 +
695 +  do
696 +  {
697 +   /*
698 +    * Check for side-channel requests...
699 +    */
700 +
701 +    backendCheckSideChannel(snmp_fd, http->hostaddr);
702 +
703 +   /*
704 +    * Build the IPP request...
705 +    */
706 +
707 +    request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
708 +    request->request.op.version[0] = version / 10;
709 +    request->request.op.version[1] = version % 10;
710 +
711 +    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
712 +                NULL, uri);
713 +
714 +    ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
715 +                  "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
716 +                 NULL, pattrs);
717 +
718 +   /*
719 +    * Do the request...
720 +    */
721 +
722 +    fputs("DEBUG: Getting supported attributes...\n", stderr);
723 +
724 +    if (http->version < HTTP_1_1)
725 +      httpReconnect(http);
726 +
727 +    if ((supported = cupsDoRequest(http, request, resource)) == NULL)
728 +      ipp_status = cupsLastError();
729 +    else
730 +      ipp_status = supported->request.status.status_code;
731 +
732 +    if (ipp_status > IPP_OK_CONFLICT)
733 +    {
734 +      if (ipp_status == IPP_PRINTER_BUSY ||
735 +         ipp_status == IPP_SERVICE_UNAVAILABLE)
736 +      {
737 +        if (contimeout && (time(NULL) - start_time) > contimeout)
738 +       {
739 +         _cupsLangPuts(stderr, _("ERROR: Printer not responding!\n"));
740 +         return (CUPS_BACKEND_FAILED);
741 +       }
742 +
743 +        recoverable = 1;
744 +
745 +       _cupsLangPrintf(stderr,
746 +                       _("WARNING: recoverable: Network host \'%s\' is busy; "
747 +                         "will retry in %d seconds...\n"),
748 +                       hostname, delay);
749 +
750 +        report_printer_state(supported, 0);
751 +
752 +       sleep(delay);
753 +
754 +       if (delay < 30)
755 +         delay += 5;
756 +      }
757 +      else if ((ipp_status == IPP_BAD_REQUEST ||
758 +               ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
759 +      {
760 +       /*
761 +       * Switch to IPP/1.0...
762 +       */
763 +
764 +       _cupsLangPrintf(stderr,
765 +                       _("INFO: Printer does not support IPP/%d.%d, trying "
766 +                         "IPP/1.0...\n"), version / 10, version % 10);
767 +       version = 10;
768 +       httpReconnect(http);
769 +      }
770 +      else if (ipp_status == IPP_NOT_FOUND)
771 +      {
772 +        _cupsLangPuts(stderr, _("ERROR: Destination printer does not exist!\n"));
773 +
774 +       if (supported)
775 +          ippDelete(supported);
776 +
777 +       return (CUPS_BACKEND_STOP);
778 +      }
779 +      else if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
780 +      {
781 +       if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
782 +                    "Negotiate", 9))
783 +         auth_info_required = "negotiate";
784 +
785 +       fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
786 +       return (CUPS_BACKEND_AUTH_REQUIRED);
787 +      }
788 +      else
789 +      {
790 +       _cupsLangPrintf(stderr,
791 +                       _("ERROR: Unable to get printer status (%s)!\n"),
792 +                       cupsLastErrorString());
793 +        sleep(10);
794 +      }
795 +
796 +      if (supported)
797 +        ippDelete(supported);
798 +
799 +      continue;
800 +    }
801 +    else if ((copies_sup = ippFindAttribute(supported, "copies-supported",
802 +                                           IPP_TAG_RANGE)) != NULL)
803 +    {
804 +     /*
805 +      * Has the "copies-supported" attribute - does it have an upper
806 +      * bound > 1?
807 +      */
808 +
809 +      if (copies_sup->values[0].range.upper <= 1)
810 +       copies_sup = NULL; /* No */
811 +    }
812 +
813 +    format_sup = ippFindAttribute(supported, "document-format-supported",
814 +                                 IPP_TAG_MIMETYPE);
815 +
816 +    if (format_sup)
817 +    {
818 +      fprintf(stderr, "DEBUG: document-format-supported (%d values)\n",
819 +             format_sup->num_values);
820 +      for (i = 0; i < format_sup->num_values; i ++)
821 +       fprintf(stderr, "DEBUG: [%d] = \"%s\"\n", i,
822 +               format_sup->values[i].string.text);
823 +    }
824 +
825 +    report_printer_state(supported, 0);
826 +  }
827 +  while (ipp_status > IPP_OK_CONFLICT);
828 +
829 + /*
830 +  * See if the printer is accepting jobs and is not stopped; if either
831 +  * condition is true and we are printing to a class, requeue the job...
832 +  */
833 +
834 +  if (getenv("CLASS") != NULL)
835 +  {
836 +    printer_state     = ippFindAttribute(supported, "printer-state",
837 +                                        IPP_TAG_ENUM);
838 +    printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs",
839 +                                        IPP_TAG_BOOLEAN);
840 +
841 +    if (printer_state == NULL ||
842 +       (printer_state->values[0].integer > IPP_PRINTER_PROCESSING &&
843 +        waitprinter) ||
844 +       printer_accepting == NULL ||
845 +       !printer_accepting->values[0].boolean)
846 +    {
847 +     /*
848 +      * If the CLASS environment variable is set, the job was submitted
849 +      * to a class and not to a specific queue.  In this case, we want
850 +      * to abort immediately so that the job can be requeued on the next
851 +      * available printer in the class.
852 +      */
853 +
854 +      _cupsLangPuts(stderr,
855 +                    _("INFO: Unable to contact printer, queuing on next "
856 +                     "printer in class...\n"));
857 +
858 +      ippDelete(supported);
859 +      httpClose(http);
860 +
861 +      if (tmpfilename[0])
862 +       unlink(tmpfilename);
863 +
864 +     /*
865 +      * Sleep 5 seconds to keep the job from requeuing too rapidly...
866 +      */
867 +
868 +      sleep(5);
869 +
870 +      return (CUPS_BACKEND_FAILED);
871 +    }
872 +  }
873 +
874 +  if (recoverable)
875 +  {
876 +   /*
877 +    * If we've shown a recoverable error make sure the printer proxies
878 +    * have a chance to see the recovered message. Not pretty but
879 +    * necessary for now...
880 +    */
881 +
882 +    fputs("INFO: recovered: \n", stderr);
883 +    sleep(5);
884 +  }
885 +
886 + /*
887 +  * See if the printer supports multiple copies...
888 +  */
889 +
890 +  copies = atoi(argv[4]);
891 +
892 +  if (copies_sup || argc < 7)
893 +  {
894 +    copies_remaining = 1;
895 +
896 +    if (argc < 7)
897 +      copies = 1;
898 +  }
899 +  else
900 +    copies_remaining = copies;
901 +
902 + /*
903 +  * Then issue the print-job request...
904 +  */
905 +
906 +  job_id  = 0;
907 +
908 +  while (copies_remaining > 0)
909 +  {
910 +   /*
911 +    * Check for side-channel requests...
912 +    */
913 +
914 +    backendCheckSideChannel(snmp_fd, http->hostaddr);
915 +
916 +   /*
917 +    * Build the IPP request...
918 +    */
919 +
920 +    if (job_cancelled)
921 +      break;
922 +
923 +    if (num_files > 1)
924 +      request = ippNewRequest(IPP_CREATE_JOB);
925 +    else
926 +      request = ippNewRequest(IPP_PRINT_JOB);
927 +
928 +    request->request.op.version[0] = version / 10;
929 +    request->request.op.version[1] = version % 10;
930 +
931 +    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
932 +                NULL, uri);
933 +
934 +    fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
935 +
936 +    if (argv[2][0])
937 +      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
938 +                   "requesting-user-name", NULL, argv[2]);
939 +
940 +    fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
941 +
942 +   /*
943 +    * Only add a "job-name" attribute if the remote server supports
944 +    * copy generation - some IPP implementations like HP's don't seem
945 +    * to like UTF-8 job names (STR #1837)...
946 +    */
947 +
948 +    if (argv[3][0] && copies_sup)
949 +      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
950 +                  argv[3]);
951 +
952 +    fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
953 +
954 +#ifdef HAVE_LIBZ
955 +    if (compression)
956 +      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
957 +                   "compression", NULL, "gzip");
958 +#endif /* HAVE_LIBZ */
959 +
960 +   /*
961 +    * Handle options on the command-line...
962 +    */
963 +
964 +    options     = NULL;
965 +    num_options = cupsParseOptions(argv[5], 0, &options);
966 +
967 +#ifdef __APPLE__
968 +    if (!strcasecmp(final_content_type, "application/pictwps") &&
969 +        num_files == 1)
970 +    {
971 +      if (format_sup != NULL)
972 +      {
973 +       for (i = 0; i < format_sup->num_values; i ++)
974 +         if (!strcasecmp(final_content_type, format_sup->values[i].string.text))
975 +           break;
976 +      }
977 +
978 +      if (format_sup == NULL || i >= format_sup->num_values)
979 +      {
980 +       /*
981 +       * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X)
982 +       * so convert the document to PostScript...
983 +       */
984 +
985 +       if (run_pictwps_filter(argv, files[0]))
986 +       {
987 +         if (pstmpname[0])
988 +           unlink(pstmpname);
989 +
990 +         if (tmpfilename[0])
991 +           unlink(tmpfilename);
992 +
993 +         return (CUPS_BACKEND_FAILED);
994 +        }
995 +
996 +        files[0] = pstmpname;
997 +
998 +       /*
999 +       * Change the MIME type to application/postscript and change the
1000 +       * number of copies to 1...
1001 +       */
1002 +
1003 +       final_content_type = "application/postscript";
1004 +       copies             = 1;
1005 +       copies_remaining   = 1;
1006 +        send_options       = 0;
1007 +      }
1008 +    }
1009 +#endif /* __APPLE__ */
1010 +
1011 +    if (format_sup != NULL)
1012 +    {
1013 +      for (i = 0; i < format_sup->num_values; i ++)
1014 +        if (!strcasecmp(final_content_type, format_sup->values[i].string.text))
1015 +          break;
1016 +
1017 +      if (i < format_sup->num_values)
1018 +        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1019 +                    "document-format", NULL, final_content_type);
1020 +    }
1021 +
1022 +    if (copies_sup && version > 10 && send_options)
1023 +    {
1024 +     /*
1025 +      * Only send options if the destination printer supports the copies
1026 +      * attribute and IPP/1.1.  This is a hack for the HP and Lexmark
1027 +      * implementations of IPP, which do not accept extension attributes
1028 +      * and incorrectly report a client-error-bad-request error instead of
1029 +      * the successful-ok-unsupported-attributes status.  In short, at least
1030 +      * some HP and Lexmark implementations of IPP are non-compliant.
1031 +      */
1032 +
1033 +      cupsEncodeOptions(request, num_options, options);
1034 +
1035 +      ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
1036 +                    copies);
1037 +    }
1038 +
1039 +    cupsFreeOptions(num_options, options);
1040 +
1041 +   /*
1042 +    * If copies aren't supported, then we are likely dealing with an HP
1043 +    * JetDirect.  The HP IPP implementation seems to close the connection
1044 +    * after every request - that is, it does *not* implement HTTP Keep-
1045 +    * Alive, which is REQUIRED by HTTP/1.1...
1046 +    */
1047 +
1048 +    if (!copies_sup)
1049 +      httpReconnect(http);
1050 +
1051 +   /*
1052 +    * Do the request...
1053 +    */
1054 +
1055 +    if (http->version < HTTP_1_1)
1056 +      httpReconnect(http);
1057 +
1058 +    if (num_files > 1)
1059 +      response = cupsDoRequest(http, request, resource);
1060 +    else
1061 +      response = cupsDoFileRequest(http, request, resource, files[0]);
1062 +
1063 +    ipp_status = cupsLastError();
1064 +
1065 +    if (ipp_status > IPP_OK_CONFLICT)
1066 +    {
1067 +      job_id = 0;
1068 +
1069 +      if (job_cancelled)
1070 +        break;
1071 +
1072 +      if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1073 +         ipp_status == IPP_PRINTER_BUSY)
1074 +      {
1075 +        _cupsLangPuts(stderr,
1076 +                     _("INFO: Printer busy; will retry in 10 seconds...\n"));
1077 +       sleep(10);
1078 +      }
1079 +      else if ((ipp_status == IPP_BAD_REQUEST ||
1080 +               ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10)
1081 +      {
1082 +       /*
1083 +       * Switch to IPP/1.0...
1084 +       */
1085 +
1086 +       _cupsLangPrintf(stderr,
1087 +                       _("INFO: Printer does not support IPP/%d.%d, trying "
1088 +                         "IPP/1.0...\n"), version / 10, version % 10);
1089 +       version = 10;
1090 +       httpReconnect(http);
1091 +      }
1092 +      else
1093 +      {
1094 +       /*
1095 +       * Update auth-info-required as needed...
1096 +       */
1097 +
1098 +        _cupsLangPrintf(stderr, _("ERROR: Print file was not accepted (%s)!\n"),
1099 +                       cupsLastErrorString());
1100 +
1101 +       if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
1102 +       {
1103 +         fprintf(stderr, "DEBUG: WWW-Authenticate=\"%s\"\n",
1104 +                 httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE));
1105 +
1106 +         /*
1107 +         * Normal authentication goes through the password callback, which sets
1108 +         * auth_info_required to "username,password".  Kerberos goes directly
1109 +         * through GSSAPI, so look for Negotiate in the WWW-Authenticate header
1110 +         * here and set auth_info_required as needed...
1111 +         */
1112 +
1113 +         if (!strncmp(httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE),
1114 +                      "Negotiate", 9))
1115 +           auth_info_required = "negotiate";
1116 +       }
1117 +      }
1118 +    }
1119 +    else if ((job_id_attr = ippFindAttribute(response, "job-id",
1120 +                                             IPP_TAG_INTEGER)) == NULL)
1121 +    {
1122 +      _cupsLangPuts(stderr,
1123 +                    _("NOTICE: Print file accepted - job ID unknown.\n"));
1124 +      job_id = 0;
1125 +    }
1126 +    else
1127 +    {
1128 +      job_id = job_id_attr->values[0].integer;
1129 +      _cupsLangPrintf(stderr, _("NOTICE: Print file accepted - job ID %d.\n"),
1130 +                      job_id);
1131 +    }
1132 +
1133 +    ippDelete(response);
1134 +
1135 +    if (job_cancelled)
1136 +      break;
1137 +
1138 +    if (job_id && num_files > 1)
1139 +    {
1140 +      for (i = 0; i < num_files; i ++)
1141 +      {
1142 +       /*
1143 +       * Check for side-channel requests...
1144 +       */
1145 +
1146 +       backendCheckSideChannel(snmp_fd, http->hostaddr);
1147 +
1148 +       /*
1149 +        * Send the next file in the job...
1150 +       */
1151 +
1152 +       request = ippNewRequest(IPP_SEND_DOCUMENT);
1153 +       request->request.op.version[0] = version / 10;
1154 +       request->request.op.version[1] = version % 10;
1155 +
1156 +       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1157 +                    NULL, uri);
1158 +
1159 +        ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1160 +                     job_id);
1161 +
1162 +       if (argv[2][0])
1163 +         ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1164 +                       "requesting-user-name", NULL, argv[2]);
1165 +
1166 +        if ((i + 1) == num_files)
1167 +         ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1);
1168 +
1169 +        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
1170 +                    "document-format", NULL, content_type);
1171 +
1172 +       if (http->version < HTTP_1_1)
1173 +         httpReconnect(http);
1174 +
1175 +        ippDelete(cupsDoFileRequest(http, request, resource, files[i]));
1176 +
1177 +       if (cupsLastError() > IPP_OK_CONFLICT)
1178 +       {
1179 +         ipp_status = cupsLastError();
1180 +
1181 +         _cupsLangPrintf(stderr,
1182 +                         _("ERROR: Unable to add file %d to job: %s\n"),
1183 +                         job_id, cupsLastErrorString());
1184 +         break;
1185 +       }
1186 +      }
1187 +    }
1188 +
1189 +    if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
1190 +    {
1191 +      fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
1192 +      copies_remaining --;
1193 +    }
1194 +    else if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
1195 +            ipp_status == IPP_PRINTER_BUSY)
1196 +      continue;
1197 +    else
1198 +      copies_remaining --;
1199 +
1200 +   /*
1201 +    * Wait for the job to complete...
1202 +    */
1203 +
1204 +    if (!job_id || !waitjob)
1205 +      continue;
1206 +
1207 +    _cupsLangPuts(stderr, _("INFO: Waiting for job to complete...\n"));
1208 +
1209 +    for (delay = 1; !job_cancelled;)
1210 +    {
1211 +     /*
1212 +      * Check for side-channel requests...
1213 +      */
1214 +
1215 +      backendCheckSideChannel(snmp_fd, http->hostaddr);
1216 +
1217 +     /*
1218 +      * Build an IPP_GET_JOB_ATTRIBUTES request...
1219 +      */
1220 +
1221 +      request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
1222 +      request->request.op.version[0] = version / 10;
1223 +      request->request.op.version[1] = version % 10;
1224 +
1225 +      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1226 +                  NULL, uri);
1227 +
1228 +      ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id",
1229 +                   job_id);
1230 +
1231 +      if (argv[2][0])
1232 +       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1233 +                    "requesting-user-name", NULL, argv[2]);
1234 +
1235 +      ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1236 +                    "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
1237 +                   NULL, jattrs);
1238 +
1239 +     /*
1240 +      * Do the request...
1241 +      */
1242 +
1243 +      if (!copies_sup || http->version < HTTP_1_1)
1244 +       httpReconnect(http);
1245 +
1246 +      response   = cupsDoRequest(http, request, resource);
1247 +      ipp_status = cupsLastError();
1248 +
1249 +      if (ipp_status == IPP_NOT_FOUND)
1250 +      {
1251 +       /*
1252 +        * Job has gone away and/or the server has no job history...
1253 +       */
1254 +
1255 +        ippDelete(response);
1256 +
1257 +       ipp_status = IPP_OK;
1258 +        break;
1259 +      }
1260 +
1261 +      if (ipp_status > IPP_OK_CONFLICT)
1262 +      {
1263 +       if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
1264 +           ipp_status != IPP_PRINTER_BUSY)
1265 +       {
1266 +         ippDelete(response);
1267 +
1268 +          _cupsLangPrintf(stderr,
1269 +                         _("ERROR: Unable to get job %d attributes (%s)!\n"),
1270 +                         job_id, cupsLastErrorString());
1271 +          break;
1272 +       }
1273 +      }
1274 +
1275 +      if (response)
1276 +      {
1277 +       if ((job_state = ippFindAttribute(response, "job-state",
1278 +                                         IPP_TAG_ENUM)) != NULL)
1279 +       {
1280 +        /*
1281 +          * Stop polling if the job is finished or pending-held...
1282 +         */
1283 +
1284 +          if (job_state->values[0].integer > IPP_JOB_STOPPED)
1285 +         {
1286 +           if ((job_sheets = ippFindAttribute(response, 
1287 +                                              "job-media-sheets-completed",
1288 +                                              IPP_TAG_INTEGER)) != NULL)
1289 +             fprintf(stderr, "PAGE: total %d\n",
1290 +                     job_sheets->values[0].integer);
1291 +
1292 +           ippDelete(response);
1293 +           break;
1294 +         }
1295 +       }
1296 +       else
1297 +       {
1298 +        /*
1299 +         * If the printer does not return a job-state attribute, it does not
1300 +         * conform to the IPP specification - break out immediately and fail
1301 +         * the job...
1302 +         */
1303 +
1304 +          fputs("DEBUG: No job-state available from printer - stopping queue.\n",
1305 +               stderr);
1306 +         ipp_status = IPP_INTERNAL_ERROR;
1307 +         break;
1308 +       }
1309 +      }
1310 +
1311 +      ippDelete(response);
1312 +
1313 +     /*
1314 +      * Check the printer state and report it if necessary...
1315 +      */
1316 +
1317 +      check_printer_state(http, uri, resource, argv[2], version, job_id);
1318 +
1319 +     /*
1320 +      * Wait 1-10 seconds before polling again...
1321 +      */
1322 +
1323 +      sleep(delay);
1324 +
1325 +      delay ++;
1326 +      if (delay > 10)
1327 +        delay = 1;
1328 +    }
1329 +  }
1330 +
1331 + /*
1332 +  * Cancel the job as needed...
1333 +  */
1334 +
1335 +  if (job_cancelled && job_id)
1336 +    cancel_job(http, uri, job_id, resource, argv[2], version);
1337 +
1338 + /*
1339 +  * Check the printer state and report it if necessary...
1340 +  */
1341 +
1342 +  check_printer_state(http, uri, resource, argv[2], version, job_id);
1343 +
1344 + /*
1345 +  * Collect the final page count as needed...
1346 +  */
1347 +
1348 +  if (have_supplies && 
1349 +      !backendSNMPSupplies(snmp_fd, http->hostaddr, &page_count, NULL) &&
1350 +      page_count > start_count)
1351 +    fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
1352 +
1353 +#ifdef HAVE_GSSAPI
1354 + /*
1355 +  * See if we used Kerberos at all...
1356 +  */
1357 +
1358 +  if (http->gssctx)
1359 +    auth_info_required = "negotiate";
1360 +#endif /* HAVE_GSSAPI */
1361 +
1362 + /*
1363 +  * Free memory...
1364 +  */
1365 +
1366 +  httpClose(http);
1367 +
1368 +  ippDelete(supported);
1369 +
1370 + /*
1371 +  * Remove the temporary file(s) if necessary...
1372 +  */
1373 +
1374 +  if (tmpfilename[0])
1375 +    unlink(tmpfilename);
1376 +
1377 +#ifdef HAVE_LIBZ
1378 +  if (compression)
1379 +  {
1380 +    for (i = 0; i < num_files; i ++)
1381 +      unlink(files[i]);
1382 +  }
1383 +#endif /* HAVE_LIBZ */
1384 +
1385 +#ifdef __APPLE__
1386 +  if (pstmpname[0])
1387 +    unlink(pstmpname);
1388 +#endif /* __APPLE__ */
1389 +
1390 + /*
1391 +  * Return the queue status...
1392 +  */
1393 +
1394 +  fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
1395 +
1396 +  if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN)
1397 +    return (CUPS_BACKEND_AUTH_REQUIRED);
1398 +  else if (ipp_status == IPP_INTERNAL_ERROR)
1399 +    return (CUPS_BACKEND_STOP);
1400 +  else if (ipp_status > IPP_OK_CONFLICT)
1401 +    return (CUPS_BACKEND_FAILED);
1402 +  else
1403 +  {
1404 +    _cupsLangPuts(stderr, _("INFO: Ready to print.\n"));
1405 +    return (CUPS_BACKEND_OK);
1406 +  }
1407 +}
1408 +
1409 +
1410 +/*
1411 + * 'cancel_job()' - Cancel a print job.
1412 + */
1413 +
1414 +static void
1415 +cancel_job(http_t     *http,           /* I - HTTP connection */
1416 +           const char *uri,            /* I - printer-uri */
1417 +          int        id,               /* I - job-id */
1418 +          const char *resource,        /* I - Resource path */
1419 +          const char *user,            /* I - requesting-user-name */
1420 +          int        version)          /* I - IPP version */
1421 +{
1422 +  ipp_t        *request;                       /* Cancel-Job request */
1423 +
1424 +
1425 +  _cupsLangPuts(stderr, _("INFO: Canceling print job...\n"));
1426 +
1427 +  request = ippNewRequest(IPP_CANCEL_JOB);
1428 +  request->request.op.version[0] = version / 10;
1429 +  request->request.op.version[1] = version % 10;
1430 +
1431 +  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1432 +               NULL, uri);
1433 +  ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", id);
1434 +
1435 +  if (user && user[0])
1436 +    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1437 +                 "requesting-user-name", NULL, user);
1438 +
1439 + /*
1440 +  * Do the request...
1441 +  */
1442 +
1443 +  if (http->version < HTTP_1_1)
1444 +    httpReconnect(http);
1445 +
1446 +  ippDelete(cupsDoRequest(http, request, resource));
1447 +
1448 +  if (cupsLastError() > IPP_OK_CONFLICT)
1449 +    _cupsLangPrintf(stderr, _("ERROR: Unable to cancel job %d: %s\n"), id,
1450 +                   cupsLastErrorString());
1451 +}
1452 +
1453 +
1454 +/*
1455 + * 'check_printer_state()' - Check the printer state...
1456 + */
1457 +
1458 +static void
1459 +check_printer_state(
1460 +    http_t      *http,                 /* I - HTTP connection */
1461 +    const char  *uri,                  /* I - Printer URI */
1462 +    const char  *resource,             /* I - Resource path */
1463 +    const char  *user,                 /* I - Username, if any */
1464 +    int         version,               /* I - IPP version */
1465 +    int         job_id)                        /* I - Current job ID */
1466 +{
1467 +  ipp_t        *request,                       /* IPP request */
1468 +       *response;                      /* IPP response */
1469 +  static const char * const attrs[] =  /* Attributes we want */
1470 +  {
1471 +    "com.apple.print.recoverable-message",
1472 +    "marker-colors",
1473 +    "marker-levels",
1474 +    "marker-message",
1475 +    "marker-names",
1476 +    "marker-types",
1477 +    "printer-state-message",
1478 +    "printer-state-reasons"
1479 +  };
1480 +
1481 +
1482 + /*
1483 +  * Check on the printer state...
1484 +  */
1485 +
1486 +  request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1487 +  request->request.op.version[0] = version / 10;
1488 +  request->request.op.version[1] = version % 10;
1489 +
1490 +  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1491 +               NULL, uri);
1492 +
1493 +  if (user && user[0])
1494 +    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1495 +                 "requesting-user-name", NULL, user);
1496 +
1497 +  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1498 +                "requested-attributes",
1499 +               (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
1500 +
1501 + /*
1502 +  * Do the request...
1503 +  */
1504 +
1505 +  if (http->version < HTTP_1_1)
1506 +    httpReconnect(http);
1507 +
1508 +  if ((response = cupsDoRequest(http, request, resource)) != NULL)
1509 +  {
1510 +    report_printer_state(response, job_id);
1511 +    ippDelete(response);
1512 +  }
1513 +}
1514 +
1515 +
1516 +#ifdef HAVE_LIBZ
1517 +/*
1518 + * 'compress_files()' - Compress print files...
1519 + */
1520 +
1521 +static void
1522 +compress_files(int  num_files,         /* I - Number of files */
1523 +               char **files)           /* I - Files */
1524 +{
1525 +  int          i,                      /* Looping var */
1526 +               fd;                     /* Temporary file descriptor */
1527 +  ssize_t      bytes;                  /* Bytes read/written */
1528 +  size_t       total;                  /* Total bytes read */
1529 +  cups_file_t  *in,                    /* Input file */
1530 +               *out;                   /* Output file */
1531 +  struct stat  outinfo;                /* Output file information */
1532 +  char         filename[1024],         /* Temporary filename */
1533 +               buffer[32768];          /* Copy buffer */
1534 +
1535 +
1536 +  fprintf(stderr, "DEBUG: Compressing %d job files...\n", num_files);
1537 +  for (i = 0; i < num_files; i ++)
1538 +  {
1539 +    if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
1540 +    {
1541 +      _cupsLangPrintf(stderr,
1542 +                     _("ERROR: Unable to create temporary compressed print "
1543 +                       "file: %s\n"), strerror(errno));
1544 +      exit(CUPS_BACKEND_FAILED);
1545 +    }
1546 +
1547 +    if ((out = cupsFileOpenFd(fd, "w9")) == NULL)
1548 +    {
1549 +      _cupsLangPrintf(stderr,
1550 +                     _("ERROR: Unable to open temporary compressed print "
1551 +                       "file: %s\n"), strerror(errno));
1552 +      exit(CUPS_BACKEND_FAILED);
1553 +    }
1554 +
1555 +    if ((in = cupsFileOpen(files[i], "r")) == NULL)
1556 +    {
1557 +      _cupsLangPrintf(stderr,
1558 +                      _("ERROR: Unable to open print file \"%s\": %s\n"),
1559 +                     files[i], strerror(errno));
1560 +      cupsFileClose(out);
1561 +      exit(CUPS_BACKEND_FAILED);
1562 +    }
1563 +
1564 +    total = 0;
1565 +    while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0)
1566 +      if (cupsFileWrite(out, buffer, bytes) < bytes)
1567 +      {
1568 +        _cupsLangPrintf(stderr,
1569 +                       _("ERROR: Unable to write %d bytes to \"%s\": %s\n"),
1570 +                       (int)bytes, filename, strerror(errno));
1571 +        cupsFileClose(in);
1572 +        cupsFileClose(out);
1573 +       exit(CUPS_BACKEND_FAILED);
1574 +      }
1575 +      else
1576 +        total += bytes;
1577 +
1578 +    cupsFileClose(out);
1579 +    cupsFileClose(in);
1580 +
1581 +    files[i] = strdup(filename);
1582 +
1583 +    if (!stat(filename, &outinfo))
1584 +      fprintf(stderr,
1585 +              "DEBUG: File %d compressed to %.1f%% of original size, "
1586 +             CUPS_LLFMT " bytes...\n",
1587 +              i + 1, 100.0 * outinfo.st_size / total,
1588 +             CUPS_LLCAST outinfo.st_size);
1589 +  }
1590 +}
1591 +#endif /* HAVE_LIBZ */
1592 +
1593 +
1594 +/*
1595 + * 'password_cb()' - Disable the password prompt for cupsDoFileRequest().
1596 + */
1597 +
1598 +static const char *                    /* O - Password  */
1599 +password_cb(const char *prompt)                /* I - Prompt (not used) */
1600 +{
1601 +  (void)prompt;
1602 +
1603 + /*
1604 +  * Remember that we need to authenticate...
1605 +  */
1606 +
1607 +  auth_info_required = "username,password";
1608 +
1609 +  if (password && *password && password_tries < 3)
1610 +  {
1611 +    password_tries ++;
1612 +
1613 +    return (password);
1614 +  }
1615 +  else
1616 +  {
1617 +   /*
1618 +    * Give up after 3 tries or if we don't have a password to begin with...
1619 +    */
1620 +
1621 +    return (NULL);
1622 +  }
1623 +}
1624 +
1625 +
1626 +/*
1627 + * 'report_attr()' - Report an IPP attribute value.
1628 + */
1629 +
1630 +static void
1631 +report_attr(ipp_attribute_t *attr)     /* I - Attribute */
1632 +{
1633 +  int  i;                              /* Looping var */
1634 +  char value[1024],                    /* Value string */
1635 +       *valptr,                        /* Pointer into value string */
1636 +       *attrptr;                       /* Pointer into attribute value */
1637 +
1638 +
1639 + /*
1640 +  * Convert the attribute values into quoted strings...
1641 +  */
1642 +
1643 +  for (i = 0, valptr = value;
1644 +       i < attr->num_values && valptr < (value + sizeof(value) - 10);
1645 +       i ++)
1646 +  {
1647 +    if (i > 0)
1648 +      *valptr++ = ',';
1649 +
1650 +    switch (attr->value_tag)
1651 +    {
1652 +      case IPP_TAG_INTEGER :
1653 +      case IPP_TAG_ENUM :
1654 +          snprintf(valptr, sizeof(value) - (valptr - value), "%d",
1655 +                  attr->values[i].integer);
1656 +         valptr += strlen(valptr);
1657 +         break;
1658 +
1659 +      case IPP_TAG_TEXT :
1660 +      case IPP_TAG_NAME :
1661 +      case IPP_TAG_KEYWORD :
1662 +          *valptr++ = '\"';
1663 +         for (attrptr = attr->values[i].string.text;
1664 +              *attrptr && valptr < (value + sizeof(value) - 10);
1665 +              attrptr ++)
1666 +         {
1667 +           if (*attrptr == '\\' || *attrptr == '\"')
1668 +             *valptr++ = '\\';
1669 +
1670 +           *valptr++ = *attrptr;
1671 +         }
1672 +          *valptr++ = '\"';
1673 +          break;
1674 +
1675 +      default :
1676 +         /*
1677 +         * Unsupported value type...
1678 +         */
1679 +
1680 +          return;
1681 +    }
1682 +  }
1683 +
1684 +  *valptr = '\0';
1685 +
1686 + /*
1687 +  * Tell the scheduler about the new values...
1688 +  */
1689 +
1690 +  fprintf(stderr, "ATTR: %s=%s\n", attr->name, value);
1691 +}
1692 +
1693 +
1694 +/*
1695 + * 'report_printer_state()' - Report the printer state.
1696 + */
1697 +
1698 +static int                             /* O - Number of reasons shown */
1699 +report_printer_state(ipp_t *ipp,       /* I - IPP response */
1700 +                     int   job_id)     /* I - Current job ID */
1701 +{
1702 +  int                  i;              /* Looping var */
1703 +  int                  count;          /* Count of reasons shown... */
1704 +  ipp_attribute_t      *caprm,         /* com.apple.print.recoverable-message */
1705 +                       *psm,           /* printer-state-message */
1706 +                       *reasons,       /* printer-state-reasons */
1707 +                       *marker;        /* marker-* attributes */
1708 +  const char           *reason;        /* Current reason */
1709 +  const char           *prefix;        /* Prefix for STATE: line */
1710 +  char                 state[1024];    /* State string */
1711 +  int                  saw_caprw;      /* Saw com.apple.print.recoverable-warning state */
1712 +
1713 +
1714 +  if ((psm = ippFindAttribute(ipp, "printer-state-message",
1715 +                              IPP_TAG_TEXT)) != NULL)
1716 +    fprintf(stderr, "INFO: %s\n", psm->values[0].string.text);
1717 +
1718 +  if ((reasons = ippFindAttribute(ipp, "printer-state-reasons",
1719 +                                  IPP_TAG_KEYWORD)) == NULL)
1720 +    return (0);
1721 +
1722 +  saw_caprw = 0;
1723 +  state[0]  = '\0';
1724 +  prefix    = "STATE: ";
1725 +
1726 +  for (i = 0, count = 0; i < reasons->num_values; i ++)
1727 +  {
1728 +    reason = reasons->values[i].string.text;
1729 +
1730 +    if (!strcmp(reason, "com.apple.print.recoverable-warning"))
1731 +      saw_caprw = 1;
1732 +    else if (strcmp(reason, "paused"))
1733 +    {
1734 +      strlcat(state, prefix, sizeof(state));
1735 +      strlcat(state, reason, sizeof(state));
1736 +
1737 +      prefix  = ",";
1738 +    }
1739 +  }
1740 +
1741 +  if (state[0])
1742 +    fprintf(stderr, "%s\n", state);
1743 +
1744 + /*
1745 +  * Relay com.apple.print.recoverable-message...
1746 +  */
1747 +
1748 +  if ((caprm = ippFindAttribute(ipp, "com.apple.print.recoverable-message",
1749 +                                IPP_TAG_TEXT)) != NULL)
1750 +    fprintf(stderr, "WARNING: %s: %s\n",
1751 +            saw_caprw ? "recoverable" : "recovered",
1752 +           caprm->values[0].string.text);
1753 +
1754 + /*
1755 +  * Relay the current marker-* attribute values...
1756 +  */
1757 +
1758 +  if ((marker = ippFindAttribute(ipp, "marker-colors", IPP_TAG_NAME)) != NULL)
1759 +    report_attr(marker);
1760 +  if ((marker = ippFindAttribute(ipp, "marker-high-levels",
1761 +                                 IPP_TAG_INTEGER)) != NULL)
1762 +    report_attr(marker);
1763 +  if ((marker = ippFindAttribute(ipp, "marker-levels",
1764 +                                 IPP_TAG_INTEGER)) != NULL)
1765 +    report_attr(marker);
1766 +  if ((marker = ippFindAttribute(ipp, "marker-low-levels",
1767 +                                 IPP_TAG_INTEGER)) != NULL)
1768 +    report_attr(marker);
1769 +  if ((marker = ippFindAttribute(ipp, "marker-message", IPP_TAG_TEXT)) != NULL)
1770 +    report_attr(marker);
1771 +  if ((marker = ippFindAttribute(ipp, "marker-names", IPP_TAG_NAME)) != NULL)
1772 +    report_attr(marker);
1773 +  if ((marker = ippFindAttribute(ipp, "marker-types", IPP_TAG_KEYWORD)) != NULL)
1774 +    report_attr(marker);
1775 +
1776 +  return (count);
1777 +}
1778 +
1779 +
1780 +#ifdef __APPLE__
1781 +/*
1782 + * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing
1783 + *                          remotely.
1784 + *
1785 + * This step is required because the PICT format is not documented and
1786 + * subject to change, so developing a filter for other OS's is infeasible.
1787 + * Also, fonts required by the PICT file need to be embedded on the
1788 + * client side (which has the fonts), so we run the filter to get a
1789 + * PostScript file for printing...
1790 + */
1791 +
1792 +static int                             /* O - Exit status of filter */
1793 +run_pictwps_filter(char       **argv,  /* I - Command-line arguments */
1794 +                   const char *filename)/* I - Filename */
1795 +{
1796 +  struct stat  fileinfo;               /* Print file information */
1797 +  const char   *ppdfile;               /* PPD file for destination printer */
1798 +  int          pid;                    /* Child process ID */
1799 +  int          fd;                     /* Temporary file descriptor */
1800 +  int          status;                 /* Exit status of filter */
1801 +  const char   *printer;               /* PRINTER env var */
1802 +  static char  ppdenv[1024];           /* PPD environment variable */
1803 +
1804 +
1805 + /*
1806 +  * First get the PPD file for the printer...
1807 +  */
1808 +
1809 +  printer = getenv("PRINTER");
1810 +  if (!printer)
1811 +  {
1812 +    _cupsLangPuts(stderr,
1813 +                  _("ERROR: PRINTER environment variable not defined!\n"));
1814 +    return (-1);
1815 +  }
1816 +
1817 +  if ((ppdfile = cupsGetPPD(printer)) == NULL)
1818 +  {
1819 +    _cupsLangPrintf(stderr,
1820 +                   _("ERROR: Unable to get PPD file for printer \"%s\" - "
1821 +                     "%s.\n"), printer, cupsLastErrorString());
1822 +  }
1823 +  else
1824 +  {
1825 +    snprintf(ppdenv, sizeof(ppdenv), "PPD=%s", ppdfile);
1826 +    putenv(ppdenv);
1827 +  }
1828 +
1829 + /*
1830 +  * Then create a temporary file for printing...
1831 +  */
1832 +
1833 +  if ((fd = cupsTempFd(pstmpname, sizeof(pstmpname))) < 0)
1834 +  {
1835 +    _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
1836 +    if (ppdfile)
1837 +      unlink(ppdfile);
1838 +    return (-1);
1839 +  }
1840 +
1841 + /*
1842 +  * Get the owner of the spool file - it is owned by the user we want to run
1843 +  * as...
1844 +  */
1845 +
1846 +  if (argv[6])
1847 +    stat(argv[6], &fileinfo);
1848 +  else
1849 +  {
1850 +   /*
1851 +    * Use the OSX defaults, as an up-stream filter created the PICT
1852 +    * file...
1853 +    */
1854 +
1855 +    fileinfo.st_uid = 1;
1856 +    fileinfo.st_gid = 80;
1857 +  }
1858 +
1859 +  if (ppdfile)
1860 +    chown(ppdfile, fileinfo.st_uid, fileinfo.st_gid);
1861 +
1862 +  fchown(fd, fileinfo.st_uid, fileinfo.st_gid);
1863 +
1864 + /*
1865 +  * Finally, run the filter to convert the file...
1866 +  */
1867 +
1868 +  if ((pid = fork()) == 0)
1869 +  {
1870 +   /*
1871 +    * Child process for pictwpstops...  Redirect output of pictwpstops to a
1872 +    * file...
1873 +    */
1874 +
1875 +    dup2(fd, 1);
1876 +    close(fd);
1877 +
1878 +    if (!getuid())
1879 +    {
1880 +     /*
1881 +      * Change to an unpriviledged user...
1882 +      */
1883 +
1884 +      if (setgid(fileinfo.st_gid))
1885 +        return (errno);
1886 +
1887 +      if (setuid(fileinfo.st_uid))
1888 +        return (errno);
1889 +    }
1890 +
1891 +    execlp("pictwpstops", printer, argv[1], argv[2], argv[3], argv[4], argv[5],
1892 +           filename, NULL);
1893 +    _cupsLangPrintf(stderr, _("ERROR: Unable to exec pictwpstops: %s\n"),
1894 +                   strerror(errno));
1895 +    return (errno);
1896 +  }
1897 +
1898 +  close(fd);
1899 +
1900 +  if (pid < 0)
1901 +  {
1902 +   /*
1903 +    * Error!
1904 +    */
1905 +
1906 +    _cupsLangPrintf(stderr, _("ERROR: Unable to fork pictwpstops: %s\n"),
1907 +                   strerror(errno));
1908 +    if (ppdfile)
1909 +      unlink(ppdfile);
1910 +    return (-1);
1911 +  }
1912 +
1913 + /*
1914 +  * Now wait for the filter to complete...
1915 +  */
1916 +
1917 +  if (wait(&status) < 0)
1918 +  {
1919 +    _cupsLangPrintf(stderr, _("ERROR: Unable to wait for pictwpstops: %s\n"),
1920 +                   strerror(errno));
1921 +    close(fd);
1922 +    if (ppdfile)
1923 +      unlink(ppdfile);
1924 +    return (-1);
1925 +  }
1926 +
1927 +  if (ppdfile)
1928 +    unlink(ppdfile);
1929 +
1930 +  close(fd);
1931 +
1932 +  if (status)
1933 +  {
1934 +    if (status >= 256)
1935 +      _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited with status %d!\n"),
1936 +                     status / 256);
1937 +    else
1938 +      _cupsLangPrintf(stderr, _("ERROR: pictwpstops exited on signal %d!\n"),
1939 +                     status);
1940 +
1941 +    return (status);
1942 +  }
1943 +
1944 + /*
1945 +  * Return with no errors..
1946 +  */
1947 +
1948 +  return (0);
1949 +}
1950 +#endif /* __APPLE__ */
1951 +
1952 +
1953 +/*
1954 + * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend.
1955 + */
1956 +
1957 +static void
1958 +sigterm_handler(int sig)               /* I - Signal */
1959 +{
1960 +  (void)sig;   /* remove compiler warnings... */
1961 +
1962 +  if (!job_cancelled)
1963 +  {
1964 +   /*
1965 +    * Flag that the job should be cancelled...
1966 +    */
1967 +
1968 +    job_cancelled = 1;
1969 +    return;
1970 +  }
1971 +
1972 + /*
1973 +  * The scheduler already tried to cancel us once, now just terminate
1974 +  * after removing our temp files!
1975 +  */
1976 +
1977 +  if (tmpfilename[0])
1978 +    unlink(tmpfilename);
1979 +
1980 +#ifdef __APPLE__
1981 +  if (pstmpname[0])
1982 +    unlink(pstmpname);
1983 +#endif /* __APPLE__ */
1984 +
1985 +  exit(1);
1986 +}
1987 +
1988 +
1989 +/*
1990 + * End of "$Id: ipp.c 8950 2010-01-14 22:40:19Z mike $".
1991 + */
This page took 0.345528 seconds and 4 git commands to generate.