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