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