]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/dest.c
faf8241b887f1e402d5da12c00cb969133382828
[thirdparty/cups.git] / cups / dest.c
1 /*
2 * "$Id: dest.c 5753 2006-07-18 19:53:24Z 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 * 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 _ipp_option_t *match; /* Matching attribute for option */
460 FILE *fp; /* File pointer */
461 const char *home; /* HOME environment variable */
462 char filename[1024]; /* lpoptions file */
463 int num_temps; /* Number of temporary destinations */
464 cups_dest_t *temps, /* Temporary destinations */
465 *temp; /* Current temporary dest */
466 const char *val; /* Value of temporary option */
467 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
468
469
470 /*
471 * Range check the input...
472 */
473
474 if (!http || !num_dests || !dests)
475 return (-1);
476
477 /*
478 * Get the server destinations...
479 */
480
481 num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, 0, &temps);
482 num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, num_temps, &temps);
483
484 /*
485 * Figure out which file to write to...
486 */
487
488 snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
489
490 #ifndef WIN32
491 if (getuid())
492 {
493 /*
494 * Merge in server defaults...
495 */
496
497 num_temps = cups_get_dests(filename, num_temps, &temps);
498
499 /*
500 * Point to user defaults...
501 */
502
503 if ((home = getenv("HOME")) != NULL)
504 {
505 /*
506 * Remove the old ~/.lpoptions file...
507 */
508
509 snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
510 unlink(filename);
511
512 /*
513 * Create ~/.cups subdirectory...
514 */
515
516 snprintf(filename, sizeof(filename), "%s/.cups", home);
517 if (access(filename, 0))
518 mkdir(filename, 0700);
519
520 snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
521 }
522 }
523 #endif /* !WIN32 */
524
525 /*
526 * Try to open the file...
527 */
528
529 if ((fp = fopen(filename, "w")) == NULL)
530 {
531 cupsFreeDests(num_temps, temps);
532 return (-1);
533 }
534
535 #ifndef WIN32
536 /*
537 * Set the permissions to 0644 when saving to the /etc/cups/lpoptions
538 * file...
539 */
540
541 if (!getuid())
542 fchmod(fileno(fp), 0644);
543 #endif /* !WIN32 */
544
545 /*
546 * Write each printer; each line looks like:
547 *
548 * Dest name[/instance] options
549 * Default name[/instance] options
550 */
551
552 for (i = num_dests, dest = dests; i > 0; i --, dest ++)
553 if (dest->instance != NULL || dest->num_options != 0 || dest->is_default)
554 {
555 if (dest->is_default)
556 {
557 fprintf(fp, "Default %s", dest->name);
558 if (dest->instance)
559 fprintf(fp, "/%s", dest->instance);
560
561 wrote = 1;
562 }
563 else
564 wrote = 0;
565
566 if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
567 temp = cupsGetDest(dest->name, NULL, num_temps, temps);
568
569 for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
570 {
571 /*
572 * See if this option is a printer attribute; if so, skip it...
573 */
574
575 if ((match = _ippFindOption(option->name)) != NULL &&
576 match->group_tag == IPP_TAG_PRINTER)
577 continue;
578
579 /*
580 * See if the server/global options match these; if so, don't
581 * write 'em.
582 */
583
584 if (temp &&
585 (val = cupsGetOption(option->name, temp->num_options,
586 temp->options)) != NULL &&
587 !strcasecmp(val, option->value))
588 continue;
589
590 /*
591 * Options don't match, write to the file...
592 */
593
594 if (!wrote)
595 {
596 fprintf(fp, "Dest %s", dest->name);
597 if (dest->instance)
598 fprintf(fp, "/%s", dest->instance);
599 wrote = 1;
600 }
601
602 if (option->value[0])
603 {
604 if (strchr(option->value, ' ') ||
605 strchr(option->value, '\\') ||
606 strchr(option->value, '\"') ||
607 strchr(option->value, '\''))
608 {
609 /*
610 * Quote the value...
611 */
612
613 fprintf(fp, " %s=\"", option->name);
614
615 for (val = option->value; *val; val ++)
616 {
617 if (strchr("\"\'\\", *val))
618 putc('\\', fp);
619
620 putc(*val, fp);
621 }
622
623 putc('\"', fp);
624 }
625 else
626 {
627 /*
628 * Store the literal value...
629 */
630
631 fprintf(fp, " %s=%s", option->name, option->value);
632 }
633 }
634 else
635 fprintf(fp, " %s", option->name);
636 }
637
638 if (wrote)
639 fputs("\n", fp);
640 }
641
642 /*
643 * Free the temporary destinations and close the file...
644 */
645
646 cupsFreeDests(num_temps, temps);
647
648 fclose(fp);
649
650 #ifdef HAVE_NOTIFY_POST
651 /*
652 * Send a notification so that MacOS X applications can know about the
653 * change, too.
654 */
655
656 notify_post("com.apple.printerListChange");
657 #endif /* HAVE_NOTIFY_POST */
658
659 return (0);
660 }
661
662
663 /*
664 * 'cups_get_dests()' - Get destinations from a file.
665 */
666
667 static int /* O - Number of destinations */
668 cups_get_dests(const char *filename, /* I - File to read from */
669 int num_dests, /* I - Number of destinations */
670 cups_dest_t **dests) /* IO - Destinations */
671 {
672 int i; /* Looping var */
673 cups_dest_t *dest; /* Current destination */
674 FILE *fp; /* File pointer */
675 char line[8192], /* Line from file */
676 *lineptr, /* Pointer into line */
677 *name, /* Name of destination/option */
678 *instance; /* Instance of destination */
679 const char *printer; /* PRINTER or LPDEST */
680
681
682 /*
683 * Check environment variables...
684 */
685
686 if ((printer = getenv("LPDEST")) == NULL)
687 if ((printer = getenv("PRINTER")) != NULL)
688 if (strcmp(printer, "lp") == 0)
689 printer = NULL;
690
691 /*
692 * Try to open the file...
693 */
694
695 if ((fp = fopen(filename, "r")) == NULL)
696 return (num_dests);
697
698 /*
699 * Read each printer; each line looks like:
700 *
701 * Dest name[/instance] options
702 * Default name[/instance] options
703 */
704
705 while (fgets(line, sizeof(line), fp) != NULL)
706 {
707 /*
708 * See what type of line it is...
709 */
710
711 if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4] & 255))
712 lineptr = line + 4;
713 else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255))
714 lineptr = line + 7;
715 else
716 continue;
717
718 /*
719 * Skip leading whitespace...
720 */
721
722 while (isspace(*lineptr & 255))
723 lineptr ++;
724
725 if (!*lineptr)
726 continue;
727
728 name = lineptr;
729
730 /*
731 * Search for an instance...
732 */
733
734 while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
735 lineptr ++;
736
737 if (!*lineptr)
738 continue;
739
740 if (*lineptr == '/')
741 {
742 /*
743 * Found an instance...
744 */
745
746 *lineptr++ = '\0';
747 instance = lineptr;
748
749 /*
750 * Search for an instance...
751 */
752
753 while (!isspace(*lineptr & 255) && *lineptr)
754 lineptr ++;
755 }
756 else
757 instance = NULL;
758
759 *lineptr++ = '\0';
760
761 /*
762 * See if the primary instance of the destination exists; if not,
763 * ignore this entry and move on...
764 */
765
766 if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
767 continue;
768
769 /*
770 * Add the destination...
771 */
772
773 num_dests = cupsAddDest(name, instance, num_dests, dests);
774
775 if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
776 {
777 /*
778 * Out of memory!
779 */
780
781 fclose(fp);
782 return (num_dests);
783 }
784
785 /*
786 * Add options until we hit the end of the line...
787 */
788
789 dest->num_options = cupsParseOptions(lineptr, dest->num_options,
790 &(dest->options));
791
792 /*
793 * Set this as default if needed...
794 */
795
796 if (strncasecmp(line, "default", 7) == 0 && printer == NULL)
797 {
798 for (i = 0; i < num_dests; i ++)
799 (*dests)[i].is_default = 0;
800
801 dest->is_default = 1;
802 }
803 }
804
805 /*
806 * Close the file and return...
807 */
808
809 fclose(fp);
810
811 return (num_dests);
812 }
813
814
815 /*
816 * 'cups_get_sdests()' - Get destinations from a server.
817 */
818
819 static int /* O - Number of destinations */
820 cups_get_sdests(http_t *http, /* I - HTTP connection */
821 ipp_op_t op, /* I - get-printers or get-classes */
822 int num_dests, /* I - Number of destinations */
823 cups_dest_t **dests) /* IO - Destinations */
824 {
825 int i; /* Looping var */
826 cups_dest_t *dest; /* Current destination */
827 ipp_t *request, /* IPP Request */
828 *response; /* IPP Response */
829 ipp_attribute_t *attr; /* Current attribute */
830 int accepting, /* printer-is-accepting-jobs attribute */
831 shared, /* printer-is-shared attribute */
832 state, /* printer-state attribute */
833 change_time, /* printer-state-change-time attribute */
834 type; /* printer-type attribute */
835 const char *info, /* printer-info attribute */
836 *make_model, /* printer-make-and-model attribute */
837 *name; /* printer-name attribute */
838 char job_sheets[1024], /* job-sheets option */
839 reasons[1024], /* printer-state-reasons attribute */
840 *rptr, /* Pointer into reasons string */
841 temp[255]; /* Temporary string for numbers */
842 static const char * const pattrs[] = /* Attributes we're interested in */
843 {
844 "job-sheets-default",
845 "printer-info",
846 "printer-is-accepting-jobs",
847 "printer-is-shared",
848 "printer-make-and-model",
849 "printer-name",
850 "printer-state",
851 "printer-state-change-time",
852 "printer-state-reasons",
853 "printer-type"
854 };
855
856
857 /*
858 * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
859 * the following attributes:
860 *
861 * attributes-charset
862 * attributes-natural-language
863 * requesting-user-name
864 */
865
866 request = ippNewRequest(op);
867
868 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
869 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
870 NULL, pattrs);
871
872 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
873 "requesting-user-name", NULL, cupsUser());
874
875 /*
876 * Do the request and get back a response...
877 */
878
879 if ((response = cupsDoRequest(http, request, "/")) != NULL)
880 {
881 for (attr = response->attrs; attr != NULL; attr = attr->next)
882 {
883 /*
884 * Skip leading attributes until we hit a printer...
885 */
886
887 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
888 attr = attr->next;
889
890 if (attr == NULL)
891 break;
892
893 /*
894 * Pull the needed attributes from this job...
895 */
896
897 accepting = 0;
898 change_time = 0;
899 info = NULL;
900 make_model = NULL;
901 name = NULL;
902 shared = 1;
903 state = IPP_PRINTER_IDLE;
904 type = CUPS_PRINTER_LOCAL;
905
906 strcpy(job_sheets, "");
907 strcpy(reasons, "");
908
909 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
910 {
911 if (!strcmp(attr->name, "job-sheets-default") &&
912 (attr->value_tag == IPP_TAG_KEYWORD ||
913 attr->value_tag == IPP_TAG_NAME))
914 {
915 if (attr->num_values == 2)
916 snprintf(job_sheets, sizeof(job_sheets), "%s,%s",
917 attr->values[0].string.text, attr->values[1].string.text);
918 else
919 strlcpy(job_sheets, attr->values[0].string.text,
920 sizeof(job_sheets));
921 }
922 else if (!strcmp(attr->name, "printer-info") &&
923 attr->value_tag == IPP_TAG_TEXT)
924 info = attr->values[0].string.text;
925 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
926 attr->value_tag == IPP_TAG_BOOLEAN)
927 accepting = attr->values[0].boolean;
928 else if (!strcmp(attr->name, "printer-is-shared") &&
929 attr->value_tag == IPP_TAG_BOOLEAN)
930 shared = attr->values[0].boolean;
931 else if (!strcmp(attr->name, "printer-make-and-model") &&
932 attr->value_tag == IPP_TAG_TEXT)
933 make_model = attr->values[0].string.text;
934 else if (!strcmp(attr->name, "printer-name") &&
935 attr->value_tag == IPP_TAG_NAME)
936 name = attr->values[0].string.text;
937 else if (!strcmp(attr->name, "printer-state") &&
938 attr->value_tag == IPP_TAG_ENUM)
939 state = attr->values[0].integer;
940 else if (!strcmp(attr->name, "printer-state-change-time") &&
941 attr->value_tag == IPP_TAG_INTEGER)
942 change_time = attr->values[0].integer;
943 else if (!strcmp(attr->name, "printer-state-reasons") &&
944 attr->value_tag == IPP_TAG_KEYWORD)
945 {
946 strlcpy(reasons, attr->values[0].string.text, sizeof(reasons));
947 for (i = 1, rptr = reasons + strlen(reasons);
948 i < attr->num_values;
949 i ++)
950 {
951 snprintf(rptr, sizeof(reasons) - (rptr - reasons), ",%s",
952 attr->values[i].string.text);
953 rptr += strlen(rptr);
954 }
955 }
956 else if (!strcmp(attr->name, "printer-type") &&
957 attr->value_tag == IPP_TAG_ENUM)
958 type = attr->values[0].integer;
959
960 attr = attr->next;
961 }
962
963 /*
964 * See if we have everything needed...
965 */
966
967 if (!name)
968 {
969 if (attr == NULL)
970 break;
971 else
972 continue;
973 }
974
975 num_dests = cupsAddDest(name, NULL, num_dests, dests);
976
977 if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL)
978 {
979 if (job_sheets[0])
980 dest->num_options = cupsAddOption("job-sheets", job_sheets,
981 dest->num_options,
982 &(dest->options));
983
984 if (info)
985 dest->num_options = cupsAddOption("printer-info", info,
986 dest->num_options,
987 &(dest->options));
988
989 sprintf(temp, "%d", accepting);
990 dest->num_options = cupsAddOption("printer-is-accepting-jobs", temp,
991 dest->num_options,
992 &(dest->options));
993
994 sprintf(temp, "%d", shared);
995 dest->num_options = cupsAddOption("printer-is-shared", temp,
996 dest->num_options,
997 &(dest->options));
998
999 if (make_model)
1000 dest->num_options = cupsAddOption("printer-make-and-model",
1001 make_model, dest->num_options,
1002 &(dest->options));
1003
1004 sprintf(temp, "%d", state);
1005 dest->num_options = cupsAddOption("printer-state", temp,
1006 dest->num_options,
1007 &(dest->options));
1008
1009 if (change_time)
1010 {
1011 sprintf(temp, "%d", change_time);
1012 dest->num_options = cupsAddOption("printer-state-change-time", temp,
1013 dest->num_options,
1014 &(dest->options));
1015 }
1016
1017 if (reasons[0])
1018 dest->num_options = cupsAddOption("printer-state-reasons", reasons,
1019 dest->num_options,
1020 &(dest->options));
1021
1022 sprintf(temp, "%d", type);
1023 dest->num_options = cupsAddOption("printer-type", temp,
1024 dest->num_options,
1025 &(dest->options));
1026 }
1027
1028 if (attr == NULL)
1029 break;
1030 }
1031
1032 ippDelete(response);
1033 }
1034
1035 /*
1036 * Return the count...
1037 */
1038
1039 return (num_dests);
1040 }
1041
1042
1043 /*
1044 * End of "$Id: dest.c 5753 2006-07-18 19:53:24Z mike $".
1045 */