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