]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/dest.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / dest.c
1 /*
2 * "$Id: dest.c 6044 2006-10-17 20:32:59Z mike $"
3 *
4 * User-defined destination (and option) support for the Common UNIX
5 * Printing System (CUPS).
6 *
7 * Copyright 1997-2006 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Easy Software Products and are protected by Federal
11 * copyright law. Distribution and use rights are outlined in the file
12 * "LICENSE.txt" which should have been included with this file. If this
13 * file is missing or damaged please contact Easy Software Products
14 * at:
15 *
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636 USA
20 *
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
24 *
25 * This file is subject to the Apple OS-Developed Software exception.
26 *
27 * Contents:
28 *
29 * cupsAddDest() - Add a destination to the list of destinations.
30 * cupsFreeDests() - Free the memory used by the list of destinations.
31 * cupsGetDest() - Get the named destination from the list.
32 * cupsGetDests() - Get the list of destinations from the default server.
33 * cupsGetDests2() - Get the list of destinations from the specified server.
34 * cupsSetDests() - Set the list of destinations for the default server.
35 * cupsSetDests2() - Set the list of destinations for the specified server.
36 * cups_get_dests() - Get destinations from a file.
37 * cups_get_sdests() - Get destinations from a server.
38 */
39
40 /*
41 * Include necessary headers...
42 */
43
44 #include "globals.h"
45 #include <stdlib.h>
46 #include <ctype.h>
47 #include <sys/stat.h>
48
49 #ifdef HAVE_NOTIFY_H
50 # include <notify.h>
51 #endif /* HAVE_NOTIFY_H */
52
53
54 /*
55 * Local functions...
56 */
57
58 static int cups_get_dests(const char *filename, int num_dests,
59 cups_dest_t **dests);
60 static int cups_get_sdests(http_t *http, ipp_op_t op, int num_dests,
61 cups_dest_t **dests);
62
63
64 /*
65 * 'cupsAddDest()' - Add a destination to the list of destinations.
66 *
67 * This function cannot be used to add a new class or printer queue,
68 * it only adds a new container of saved options for the named
69 * destination or instance.
70 *
71 * If the named destination already exists, the destination list is
72 * returned unchanged. Adding a new instance of a destination creates
73 * a copy of that destination's options.
74 *
75 * Use the cupsSaveDests() function to save the updated list of
76 * destinations to the user's lpoptions file.
77 */
78
79 int /* O - New number of destinations */
80 cupsAddDest(const char *name, /* I - Destination name */
81 const char *instance, /* I - Instance name or NULL for none/primary */
82 int num_dests, /* I - Number of destinations */
83 cups_dest_t **dests) /* IO - Destinations */
84 {
85 int i; /* Looping var */
86 cups_dest_t *dest; /* Destination pointer */
87 cups_dest_t *parent; /* Parent destination */
88 cups_option_t *option; /* Current option */
89
90
91 if (!name || !dests)
92 return (0);
93
94 if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
95 return (num_dests);
96
97 /*
98 * Add new destination...
99 */
100
101 if (num_dests == 0)
102 dest = malloc(sizeof(cups_dest_t));
103 else
104 dest = realloc(*dests, sizeof(cups_dest_t) * (num_dests + 1));
105
106 if (dest == NULL)
107 return (num_dests);
108
109 *dests = dest;
110
111 /*
112 * Find where to insert the destination...
113 */
114
115 for (i = num_dests; i > 0; i --, dest ++)
116 if (strcasecmp(name, dest->name) < 0)
117 break;
118 else if (!instance && dest->instance)
119 break;
120 else if (!strcasecmp(name, dest->name) &&
121 instance && dest->instance &&
122 strcasecmp(instance, dest->instance) < 0)
123 break;
124
125 if (i > 0)
126 memmove(dest + 1, dest, i * sizeof(cups_dest_t));
127
128 /*
129 * Initialize the destination...
130 */
131
132 dest->name = strdup(name);
133 dest->is_default = 0;
134 dest->num_options = 0;
135 dest->options = (cups_option_t *)0;
136
137 if (!instance)
138 dest->instance = NULL;
139 else
140 {
141 /*
142 * Copy options from the primary instance...
143 */
144
145 dest->instance = strdup(instance);
146
147 if ((parent = cupsGetDest(name, NULL, num_dests + 1, *dests)) != NULL)
148 {
149 for (i = parent->num_options, option = parent->options;
150 i > 0;
151 i --, option ++)
152 dest->num_options = cupsAddOption(option->name, option->value,
153 dest->num_options,
154 &(dest->options));
155 }
156 }
157
158 return (num_dests + 1);
159 }
160
161
162 /*
163 * 'cupsFreeDests()' - Free the memory used by the list of destinations.
164 */
165
166 void
167 cupsFreeDests(int num_dests, /* I - Number of destinations */
168 cups_dest_t *dests) /* I - Destinations */
169 {
170 int i; /* Looping var */
171 cups_dest_t *dest; /* Current destination */
172
173
174 if (num_dests == 0 || dests == NULL)
175 return;
176
177 for (i = num_dests, dest = dests; i > 0; i --, dest ++)
178 {
179 free(dest->name);
180
181 if (dest->instance)
182 free(dest->instance);
183
184 cupsFreeOptions(dest->num_options, dest->options);
185 }
186
187 free(dests);
188 }
189
190
191 /*
192 * 'cupsGetDest()' - Get the named destination from the list.
193 *
194 * Use the cupsGetDests() or cupsGetDests2() functions to get a
195 * list of supported destinations for the current user.
196 */
197
198 cups_dest_t * /* O - Destination pointer or NULL */
199 cupsGetDest(const char *name, /* I - Destination name or NULL for the default destination */
200 const char *instance, /* I - Instance name or NULL */
201 int num_dests, /* I - Number of destinations */
202 cups_dest_t *dests) /* I - Destinations */
203 {
204 int comp; /* Result of comparison */
205
206
207 if (num_dests <= 0 || !dests)
208 return (NULL);
209
210 if (!name)
211 {
212 /*
213 * NULL name for default printer.
214 */
215
216 while (num_dests > 0)
217 {
218 if (dests->is_default)
219 return (dests);
220
221 num_dests --;
222 dests ++;
223 }
224 }
225 else
226 {
227 /*
228 * Lookup name and optionally the instance...
229 */
230
231 while (num_dests > 0)
232 {
233 if ((comp = strcasecmp(name, dests->name)) < 0)
234 return (NULL);
235 else if (comp == 0)
236 {
237 if ((!instance && !dests->instance) ||
238 (instance != NULL && dests->instance != NULL &&
239 !strcasecmp(instance, dests->instance)))
240 return (dests);
241 }
242
243 num_dests --;
244 dests ++;
245 }
246 }
247
248 return (NULL);
249 }
250
251
252 /*
253 * 'cupsGetDests()' - Get the list of destinations from the default server.
254 *
255 * Starting with CUPS 1.2, the returned list of destinations include the
256 * printer-info, printer-is-accepting-jobs, printer-is-shared,
257 * printer-make-and-model, printer-state, printer-state-change-time,
258 * printer-state-reasons, and printer-type attributes as options.
259 *
260 * Use the cupsFreeDests() function to free the destination list and
261 * the cupsGetDest() function to find a particular destination.
262 */
263
264 int /* O - Number of destinations */
265 cupsGetDests(cups_dest_t **dests) /* O - Destinations */
266 {
267 int num_dests; /* Number of destinations */
268 http_t *http; /* HTTP connection */
269
270
271 /*
272 * Connect to the CUPS server and get the destination list and options...
273 */
274
275 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
276
277 num_dests = cupsGetDests2(http, dests);
278
279 if (http)
280 httpClose(http);
281
282 return (num_dests);
283 }
284
285
286 /*
287 * 'cupsGetDests2()' - Get the list of destinations from the specified server.
288 *
289 * Starting with CUPS 1.2, the returned list of destinations include the
290 * printer-info, printer-is-accepting-jobs, printer-is-shared,
291 * printer-make-and-model, printer-state, printer-state-change-time,
292 * printer-state-reasons, and printer-type attributes as options.
293 *
294 * Use the cupsFreeDests() function to free the destination list and
295 * the cupsGetDest() function to find a particular destination.
296 *
297 * @since CUPS 1.1.21@
298 */
299
300 int /* O - Number of destinations */
301 cupsGetDests2(http_t *http, /* I - HTTP connection */
302 cups_dest_t **dests) /* O - Destinations */
303 {
304 int i; /* Looping var */
305 int num_dests; /* Number of destinations */
306 cups_dest_t *dest; /* Destination pointer */
307 const char *home; /* HOME environment variable */
308 char filename[1024]; /* Local ~/.cups/lpoptions file */
309 const char *defprinter; /* Default printer */
310 char name[1024], /* Copy of printer name */
311 *instance; /* Pointer to instance name */
312 int num_reals; /* Number of real queues */
313 cups_dest_t *reals; /* Real queues */
314 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
315
316
317 /*
318 * Range check the input...
319 */
320
321 if (!http || !dests)
322 return (0);
323
324 /*
325 * Initialize destination array...
326 */
327
328 num_dests = 0;
329 *dests = (cups_dest_t *)0;
330
331 /*
332 * Grab the printers and classes...
333 */
334
335 num_dests = cups_get_sdests(http, CUPS_GET_PRINTERS, num_dests, dests);
336 num_dests = cups_get_sdests(http, CUPS_GET_CLASSES, num_dests, dests);
337
338 /*
339 * Make a copy of the "real" queues for a later sanity check...
340 */
341
342 if (num_dests > 0)
343 {
344 num_reals = num_dests;
345 reals = calloc(num_reals, sizeof(cups_dest_t));
346
347 if (reals)
348 memcpy(reals, *dests, num_reals * sizeof(cups_dest_t));
349 else
350 num_reals = 0;
351 }
352 else
353 {
354 num_reals = 0;
355 reals = NULL;
356 }
357
358 /*
359 * Grab the default destination...
360 */
361
362 if ((defprinter = cupsGetDefault2(http)) != NULL)
363 {
364 /*
365 * Grab printer and instance name...
366 */
367
368 strlcpy(name, defprinter, sizeof(name));
369
370 if ((instance = strchr(name, '/')) != NULL)
371 *instance++ = '\0';
372
373 /*
374 * Lookup the printer and instance and make it the default...
375 */
376
377 if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
378 dest->is_default = 1;
379 }
380 else
381 {
382 /*
383 * This initialization of "instance" is unnecessary, but avoids a
384 * compiler warning...
385 */
386
387 instance = NULL;
388 }
389
390 /*
391 * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
392 */
393
394 snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
395 num_dests = cups_get_dests(filename, num_dests, dests);
396
397 if ((home = getenv("HOME")) != NULL)
398 {
399 snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
400 if (access(filename, 0))
401 snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
402
403 num_dests = cups_get_dests(filename, num_dests, dests);
404 }
405
406 /*
407 * Validate the current default destination - this prevents old
408 * Default lines in /etc/cups/lpoptions and ~/.cups/lpoptions from
409 * pointing to a non-existent printer or class...
410 */
411
412 if (num_reals)
413 {
414 /*
415 * See if we have a default printer...
416 */
417
418 if ((dest = cupsGetDest(NULL, NULL, num_dests, *dests)) != NULL)
419 {
420 /*
421 * Have a default; see if it is real...
422 */
423
424 dest = cupsGetDest(dest->name, NULL, num_reals, reals);
425 }
426
427 /*
428 * If dest is NULL, then no default (that exists) is set, so we
429 * need to set a default if one exists...
430 */
431
432 if (dest == NULL && defprinter != NULL)
433 {
434 for (i = 0; i < num_dests; i ++)
435 (*dests)[i].is_default = 0;
436
437 if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
438 dest->is_default = 1;
439 }
440
441 /*
442 * Free memory...
443 */
444
445 free(reals);
446 }
447
448 /*
449 * Return the number of destinations...
450 */
451
452 return (num_dests);
453 }
454
455
456 /*
457 * 'cupsSetDests()' - Save the list of destinations for the default server.
458 *
459 * This function saves the destinations to /etc/cups/lpoptions when run
460 * as root and ~/.cups/lpoptions when run as a normal user.
461 */
462
463 void
464 cupsSetDests(int num_dests, /* I - Number of destinations */
465 cups_dest_t *dests) /* I - Destinations */
466 {
467 http_t *http; /* HTTP connection */
468
469
470 /*
471 * Connect to the CUPS server and save the destination list and options...
472 */
473
474 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
475
476 cupsSetDests2(http, num_dests, dests);
477
478 if (http)
479 httpClose(http);
480 }
481
482
483 /*
484 * 'cupsSetDests2()' - Save the list of destinations for the specified server.
485 *
486 * This function saves the destinations to /etc/cups/lpoptions when run
487 * as root and ~/.cups/lpoptions when run as a normal user.
488 *
489 * @since CUPS 1.1.21@
490 */
491
492 int /* O - 0 on success, -1 on error */
493 cupsSetDests2(http_t *http, /* I - HTTP connection */
494 int num_dests, /* I - Number of destinations */
495 cups_dest_t *dests) /* I - Destinations */
496 {
497 int i, j; /* Looping vars */
498 int wrote; /* Wrote definition? */
499 cups_dest_t *dest; /* Current destination */
500 cups_option_t *option; /* Current option */
501 _ipp_option_t *match; /* Matching attribute for option */
502 FILE *fp; /* File pointer */
503 const char *home; /* HOME environment variable */
504 char filename[1024]; /* lpoptions file */
505 int num_temps; /* Number of temporary destinations */
506 cups_dest_t *temps, /* Temporary destinations */
507 *temp; /* Current temporary dest */
508 const char *val; /* Value of temporary option */
509 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
510
511
512 /*
513 * Range check the input...
514 */
515
516 if (!http || !num_dests || !dests)
517 return (-1);
518
519 /*
520 * Get the server destinations...
521 */
522
523 num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, 0, &temps);
524 num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, num_temps, &temps);
525
526 /*
527 * Figure out which file to write to...
528 */
529
530 snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
531
532 #ifndef WIN32
533 if (getuid())
534 {
535 /*
536 * Merge in server defaults...
537 */
538
539 num_temps = cups_get_dests(filename, num_temps, &temps);
540
541 /*
542 * Point to user defaults...
543 */
544
545 if ((home = getenv("HOME")) != NULL)
546 {
547 /*
548 * Remove the old ~/.lpoptions file...
549 */
550
551 snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
552 unlink(filename);
553
554 /*
555 * Create ~/.cups subdirectory...
556 */
557
558 snprintf(filename, sizeof(filename), "%s/.cups", home);
559 if (access(filename, 0))
560 mkdir(filename, 0700);
561
562 snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
563 }
564 }
565 #endif /* !WIN32 */
566
567 /*
568 * Try to open the file...
569 */
570
571 if ((fp = fopen(filename, "w")) == NULL)
572 {
573 cupsFreeDests(num_temps, temps);
574 return (-1);
575 }
576
577 #ifndef WIN32
578 /*
579 * Set the permissions to 0644 when saving to the /etc/cups/lpoptions
580 * file...
581 */
582
583 if (!getuid())
584 fchmod(fileno(fp), 0644);
585 #endif /* !WIN32 */
586
587 /*
588 * Write each printer; each line looks like:
589 *
590 * Dest name[/instance] options
591 * Default name[/instance] options
592 */
593
594 for (i = num_dests, dest = dests; i > 0; i --, dest ++)
595 if (dest->instance != NULL || dest->num_options != 0 || dest->is_default)
596 {
597 if (dest->is_default)
598 {
599 fprintf(fp, "Default %s", dest->name);
600 if (dest->instance)
601 fprintf(fp, "/%s", dest->instance);
602
603 wrote = 1;
604 }
605 else
606 wrote = 0;
607
608 if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
609 temp = cupsGetDest(dest->name, NULL, num_temps, temps);
610
611 for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
612 {
613 /*
614 * See if this option is a printer attribute; if so, skip it...
615 */
616
617 if ((match = _ippFindOption(option->name)) != NULL &&
618 match->group_tag == IPP_TAG_PRINTER)
619 continue;
620
621 /*
622 * See if the server/global options match these; if so, don't
623 * write 'em.
624 */
625
626 if (temp &&
627 (val = cupsGetOption(option->name, temp->num_options,
628 temp->options)) != NULL &&
629 !strcasecmp(val, option->value))
630 continue;
631
632 /*
633 * Options don't match, write to the file...
634 */
635
636 if (!wrote)
637 {
638 fprintf(fp, "Dest %s", dest->name);
639 if (dest->instance)
640 fprintf(fp, "/%s", dest->instance);
641 wrote = 1;
642 }
643
644 if (option->value[0])
645 {
646 if (strchr(option->value, ' ') ||
647 strchr(option->value, '\\') ||
648 strchr(option->value, '\"') ||
649 strchr(option->value, '\''))
650 {
651 /*
652 * Quote the value...
653 */
654
655 fprintf(fp, " %s=\"", option->name);
656
657 for (val = option->value; *val; val ++)
658 {
659 if (strchr("\"\'\\", *val))
660 putc('\\', fp);
661
662 putc(*val, fp);
663 }
664
665 putc('\"', fp);
666 }
667 else
668 {
669 /*
670 * Store the literal value...
671 */
672
673 fprintf(fp, " %s=%s", option->name, option->value);
674 }
675 }
676 else
677 fprintf(fp, " %s", option->name);
678 }
679
680 if (wrote)
681 fputs("\n", fp);
682 }
683
684 /*
685 * Free the temporary destinations and close the file...
686 */
687
688 cupsFreeDests(num_temps, temps);
689
690 fclose(fp);
691
692 #ifdef HAVE_NOTIFY_POST
693 /*
694 * Send a notification so that MacOS X applications can know about the
695 * change, too.
696 */
697
698 notify_post("com.apple.printerListChange");
699 #endif /* HAVE_NOTIFY_POST */
700
701 return (0);
702 }
703
704
705 /*
706 * 'cups_get_dests()' - Get destinations from a file.
707 */
708
709 static int /* O - Number of destinations */
710 cups_get_dests(const char *filename, /* I - File to read from */
711 int num_dests, /* I - Number of destinations */
712 cups_dest_t **dests) /* IO - Destinations */
713 {
714 int i; /* Looping var */
715 cups_dest_t *dest; /* Current destination */
716 FILE *fp; /* File pointer */
717 char line[8192], /* Line from file */
718 *lineptr, /* Pointer into line */
719 *name, /* Name of destination/option */
720 *instance; /* Instance of destination */
721 const char *printer; /* PRINTER or LPDEST */
722
723
724 /*
725 * Check environment variables...
726 */
727
728 if ((printer = getenv("LPDEST")) == NULL)
729 if ((printer = getenv("PRINTER")) != NULL)
730 if (strcmp(printer, "lp") == 0)
731 printer = NULL;
732
733 /*
734 * Try to open the file...
735 */
736
737 if ((fp = fopen(filename, "r")) == NULL)
738 return (num_dests);
739
740 /*
741 * Read each printer; each line looks like:
742 *
743 * Dest name[/instance] options
744 * Default name[/instance] options
745 */
746
747 while (fgets(line, sizeof(line), fp) != NULL)
748 {
749 /*
750 * See what type of line it is...
751 */
752
753 if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4] & 255))
754 lineptr = line + 4;
755 else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255))
756 lineptr = line + 7;
757 else
758 continue;
759
760 /*
761 * Skip leading whitespace...
762 */
763
764 while (isspace(*lineptr & 255))
765 lineptr ++;
766
767 if (!*lineptr)
768 continue;
769
770 name = lineptr;
771
772 /*
773 * Search for an instance...
774 */
775
776 while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
777 lineptr ++;
778
779 if (!*lineptr)
780 continue;
781
782 if (*lineptr == '/')
783 {
784 /*
785 * Found an instance...
786 */
787
788 *lineptr++ = '\0';
789 instance = lineptr;
790
791 /*
792 * Search for an instance...
793 */
794
795 while (!isspace(*lineptr & 255) && *lineptr)
796 lineptr ++;
797 }
798 else
799 instance = NULL;
800
801 *lineptr++ = '\0';
802
803 /*
804 * See if the primary instance of the destination exists; if not,
805 * ignore this entry and move on...
806 */
807
808 if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
809 continue;
810
811 /*
812 * Add the destination...
813 */
814
815 num_dests = cupsAddDest(name, instance, num_dests, dests);
816
817 if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
818 {
819 /*
820 * Out of memory!
821 */
822
823 fclose(fp);
824 return (num_dests);
825 }
826
827 /*
828 * Add options until we hit the end of the line...
829 */
830
831 dest->num_options = cupsParseOptions(lineptr, dest->num_options,
832 &(dest->options));
833
834 /*
835 * Set this as default if needed...
836 */
837
838 if (strncasecmp(line, "default", 7) == 0 && printer == NULL)
839 {
840 for (i = 0; i < num_dests; i ++)
841 (*dests)[i].is_default = 0;
842
843 dest->is_default = 1;
844 }
845 }
846
847 /*
848 * Close the file and return...
849 */
850
851 fclose(fp);
852
853 return (num_dests);
854 }
855
856
857 /*
858 * 'cups_get_sdests()' - Get destinations from a server.
859 */
860
861 static int /* O - Number of destinations */
862 cups_get_sdests(http_t *http, /* I - HTTP connection */
863 ipp_op_t op, /* I - get-printers or get-classes */
864 int num_dests, /* I - Number of destinations */
865 cups_dest_t **dests) /* IO - Destinations */
866 {
867 int i; /* Looping var */
868 cups_dest_t *dest; /* Current destination */
869 ipp_t *request, /* IPP Request */
870 *response; /* IPP Response */
871 ipp_attribute_t *attr; /* Current attribute */
872 int accepting, /* printer-is-accepting-jobs attribute */
873 shared, /* printer-is-shared attribute */
874 state, /* printer-state attribute */
875 change_time, /* printer-state-change-time attribute */
876 type; /* printer-type attribute */
877 const char *info, /* printer-info attribute */
878 *make_model, /* printer-make-and-model attribute */
879 *name; /* printer-name attribute */
880 char job_sheets[1024], /* job-sheets option */
881 reasons[1024], /* printer-state-reasons attribute */
882 *rptr, /* Pointer into reasons string */
883 temp[255]; /* Temporary string for numbers */
884 static const char * const pattrs[] = /* Attributes we're interested in */
885 {
886 "job-sheets-default",
887 "printer-info",
888 "printer-is-accepting-jobs",
889 "printer-is-shared",
890 "printer-make-and-model",
891 "printer-name",
892 "printer-state",
893 "printer-state-change-time",
894 "printer-state-reasons",
895 "printer-type"
896 };
897
898
899 /*
900 * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
901 * the following attributes:
902 *
903 * attributes-charset
904 * attributes-natural-language
905 * requesting-user-name
906 */
907
908 request = ippNewRequest(op);
909
910 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
911 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
912 NULL, pattrs);
913
914 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
915 "requesting-user-name", NULL, cupsUser());
916
917 /*
918 * Do the request and get back a response...
919 */
920
921 if ((response = cupsDoRequest(http, request, "/")) != NULL)
922 {
923 for (attr = response->attrs; attr != NULL; attr = attr->next)
924 {
925 /*
926 * Skip leading attributes until we hit a printer...
927 */
928
929 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
930 attr = attr->next;
931
932 if (attr == NULL)
933 break;
934
935 /*
936 * Pull the needed attributes from this job...
937 */
938
939 accepting = 0;
940 change_time = 0;
941 info = NULL;
942 make_model = NULL;
943 name = NULL;
944 shared = 1;
945 state = IPP_PRINTER_IDLE;
946 type = CUPS_PRINTER_LOCAL;
947
948 strcpy(job_sheets, "");
949 strcpy(reasons, "");
950
951 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
952 {
953 if (!strcmp(attr->name, "job-sheets-default") &&
954 (attr->value_tag == IPP_TAG_KEYWORD ||
955 attr->value_tag == IPP_TAG_NAME))
956 {
957 if (attr->num_values == 2)
958 snprintf(job_sheets, sizeof(job_sheets), "%s,%s",
959 attr->values[0].string.text, attr->values[1].string.text);
960 else
961 strlcpy(job_sheets, attr->values[0].string.text,
962 sizeof(job_sheets));
963 }
964 else if (!strcmp(attr->name, "printer-info") &&
965 attr->value_tag == IPP_TAG_TEXT)
966 info = attr->values[0].string.text;
967 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
968 attr->value_tag == IPP_TAG_BOOLEAN)
969 accepting = attr->values[0].boolean;
970 else if (!strcmp(attr->name, "printer-is-shared") &&
971 attr->value_tag == IPP_TAG_BOOLEAN)
972 shared = attr->values[0].boolean;
973 else if (!strcmp(attr->name, "printer-make-and-model") &&
974 attr->value_tag == IPP_TAG_TEXT)
975 make_model = attr->values[0].string.text;
976 else if (!strcmp(attr->name, "printer-name") &&
977 attr->value_tag == IPP_TAG_NAME)
978 name = attr->values[0].string.text;
979 else if (!strcmp(attr->name, "printer-state") &&
980 attr->value_tag == IPP_TAG_ENUM)
981 state = attr->values[0].integer;
982 else if (!strcmp(attr->name, "printer-state-change-time") &&
983 attr->value_tag == IPP_TAG_INTEGER)
984 change_time = attr->values[0].integer;
985 else if (!strcmp(attr->name, "printer-state-reasons") &&
986 attr->value_tag == IPP_TAG_KEYWORD)
987 {
988 strlcpy(reasons, attr->values[0].string.text, sizeof(reasons));
989 for (i = 1, rptr = reasons + strlen(reasons);
990 i < attr->num_values;
991 i ++)
992 {
993 snprintf(rptr, sizeof(reasons) - (rptr - reasons), ",%s",
994 attr->values[i].string.text);
995 rptr += strlen(rptr);
996 }
997 }
998 else if (!strcmp(attr->name, "printer-type") &&
999 attr->value_tag == IPP_TAG_ENUM)
1000 type = attr->values[0].integer;
1001
1002 attr = attr->next;
1003 }
1004
1005 /*
1006 * See if we have everything needed...
1007 */
1008
1009 if (!name)
1010 {
1011 if (attr == NULL)
1012 break;
1013 else
1014 continue;
1015 }
1016
1017 num_dests = cupsAddDest(name, NULL, num_dests, dests);
1018
1019 if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL)
1020 {
1021 if (job_sheets[0])
1022 dest->num_options = cupsAddOption("job-sheets", job_sheets,
1023 dest->num_options,
1024 &(dest->options));
1025
1026 if (info)
1027 dest->num_options = cupsAddOption("printer-info", info,
1028 dest->num_options,
1029 &(dest->options));
1030
1031 sprintf(temp, "%d", accepting);
1032 dest->num_options = cupsAddOption("printer-is-accepting-jobs", temp,
1033 dest->num_options,
1034 &(dest->options));
1035
1036 sprintf(temp, "%d", shared);
1037 dest->num_options = cupsAddOption("printer-is-shared", temp,
1038 dest->num_options,
1039 &(dest->options));
1040
1041 if (make_model)
1042 dest->num_options = cupsAddOption("printer-make-and-model",
1043 make_model, dest->num_options,
1044 &(dest->options));
1045
1046 sprintf(temp, "%d", state);
1047 dest->num_options = cupsAddOption("printer-state", temp,
1048 dest->num_options,
1049 &(dest->options));
1050
1051 if (change_time)
1052 {
1053 sprintf(temp, "%d", change_time);
1054 dest->num_options = cupsAddOption("printer-state-change-time", temp,
1055 dest->num_options,
1056 &(dest->options));
1057 }
1058
1059 if (reasons[0])
1060 dest->num_options = cupsAddOption("printer-state-reasons", reasons,
1061 dest->num_options,
1062 &(dest->options));
1063
1064 sprintf(temp, "%d", type);
1065 dest->num_options = cupsAddOption("printer-type", temp,
1066 dest->num_options,
1067 &(dest->options));
1068 }
1069
1070 if (attr == NULL)
1071 break;
1072 }
1073
1074 ippDelete(response);
1075 }
1076
1077 /*
1078 * Return the count...
1079 */
1080
1081 return (num_dests);
1082 }
1083
1084
1085 /*
1086 * End of "$Id: dest.c 6044 2006-10-17 20:32:59Z mike $".
1087 */