]> 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/*
b423cd4c 2 * "$Id: dest.c 5182 2006-02-26 04:10:27Z 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>
b423cd4c 47#include <sys/stat.h>
ef416fc2 48
fa73b229 49#ifdef HAVE_NOTIFY_H
50# include <notify.h>
51#endif /* HAVE_NOTIFY_H */
52
ef416fc2 53
54/*
55 * Local functions...
56 */
57
58static int cups_get_dests(const char *filename, int num_dests,
59 cups_dest_t **dests);
60static 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
71int /* O - New number of destinations */
72cupsAddDest(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;
b423cd4c 104 else if (!strcasecmp(name, dest->name) &&
ef416fc2 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
130void
131cupsFreeDests(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
162cups_dest_t * /* O - Destination pointer or NULL */
163cupsGetDest(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.
ecdc0628 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.
ef416fc2 223 */
224
225int /* O - Number of destinations */
226cupsGetDests(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 *
ecdc0628 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 *
ef416fc2 255 * @since CUPS 1.1.21@
256 */
257
258int /* O - Number of destinations */
259cupsGetDests2(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 */
b423cd4c 266 char filename[1024]; /* Local ~/.cups/lpoptions file */
ef416fc2 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 /*
b423cd4c 349 * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
ef416fc2 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 {
b423cd4c 357 snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
358 if (access(filename, 0))
359 snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
360
ef416fc2 361 num_dests = cups_get_dests(filename, num_dests, dests);
362 }
363
364 /*
365 * Validate the current default destination - this prevents old
b423cd4c 366 * Default lines in /etc/cups/lpoptions and ~/.cups/lpoptions from
ef416fc2 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
b423cd4c 418 * as root and ~/.cups/lpoptions when run as a normal user.
ef416fc2 419 */
420
421void
422cupsSetDests(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
b423cd4c 445 * as root and ~/.cups/lpoptions when run as a normal user.
ef416fc2 446 *
447 * @since CUPS 1.1.21@
448 */
449
450int /* O - 0 on success, -1 on error */
451cupsSetDests2(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)
b423cd4c 503 {
504 /*
505 * Remove the old ~/.lpoptions file...
506 */
507
ef416fc2 508 snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
b423cd4c 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 }
ef416fc2 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 /*
535 * Write each printer; each line looks like:
536 *
537 * Dest name[/instance] options
538 * Default name[/instance] options
539 */
540
541 for (i = num_dests, dest = dests; i > 0; i --, dest ++)
542 if (dest->instance != NULL || dest->num_options != 0 || dest->is_default)
543 {
544 if (dest->is_default)
545 {
546 fprintf(fp, "Default %s", dest->name);
547 if (dest->instance)
548 fprintf(fp, "/%s", dest->instance);
549
550 wrote = 1;
551 }
552 else
553 wrote = 0;
554
555 if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
556 temp = cupsGetDest(dest->name, NULL, num_temps, temps);
557
558 for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
559 {
560 /*
561 * See if the server/global options match these; if so, don't
562 * write 'em.
563 */
564
565 if (temp && (val = cupsGetOption(option->name, temp->num_options,
566 temp->options)) != NULL)
567 {
b423cd4c 568 if (!strcasecmp(val, option->value))
ef416fc2 569 continue;
570 }
571
572 /*
573 * Options don't match, write to the file...
574 */
575
576 if (!wrote)
577 {
578 fprintf(fp, "Dest %s", dest->name);
579 if (dest->instance)
580 fprintf(fp, "/%s", dest->instance);
581 wrote = 1;
582 }
583
584 if (option->value[0])
585 {
586 if (strchr(option->value, ' ') != NULL)
587 fprintf(fp, " %s=\"%s\"", option->name, option->value);
588 else
589 fprintf(fp, " %s=%s", option->name, option->value);
590 }
591 else
592 fprintf(fp, " %s", option->name);
593 }
594
595 if (wrote)
596 fputs("\n", fp);
597 }
598
599 /*
fa73b229 600 * Free the temporary destinations and close the file...
ef416fc2 601 */
602
603 cupsFreeDests(num_temps, temps);
604
fa73b229 605 fclose(fp);
606
607#ifdef HAVE_NOTIFY_POST
ef416fc2 608 /*
fa73b229 609 * Send a notification so that MacOS X applications can know about the
610 * change, too.
ef416fc2 611 */
612
fa73b229 613 notify_post("com.apple.printerListChange");
614#endif /* HAVE_NOTIFY_POST */
ef416fc2 615
616 return (0);
617}
618
619
620/*
621 * 'cups_get_dests()' - Get destinations from a file.
622 */
623
624static int /* O - Number of destinations */
625cups_get_dests(const char *filename, /* I - File to read from */
626 int num_dests, /* I - Number of destinations */
627 cups_dest_t **dests) /* IO - Destinations */
628{
629 int i; /* Looping var */
630 cups_dest_t *dest; /* Current destination */
631 FILE *fp; /* File pointer */
632 char line[8192], /* Line from file */
633 *lineptr, /* Pointer into line */
634 *name, /* Name of destination/option */
635 *instance; /* Instance of destination */
636 const char *printer; /* PRINTER or LPDEST */
637
638
639 /*
640 * Check environment variables...
641 */
642
643 if ((printer = getenv("LPDEST")) == NULL)
644 if ((printer = getenv("PRINTER")) != NULL)
645 if (strcmp(printer, "lp") == 0)
646 printer = NULL;
647
648 /*
649 * Try to open the file...
650 */
651
652 if ((fp = fopen(filename, "r")) == NULL)
653 return (num_dests);
654
655 /*
656 * Read each printer; each line looks like:
657 *
658 * Dest name[/instance] options
659 * Default name[/instance] options
660 */
661
662 while (fgets(line, sizeof(line), fp) != NULL)
663 {
664 /*
665 * See what type of line it is...
666 */
667
668 if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4] & 255))
669 lineptr = line + 4;
670 else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255))
671 lineptr = line + 7;
672 else
673 continue;
674
675 /*
676 * Skip leading whitespace...
677 */
678
679 while (isspace(*lineptr & 255))
680 lineptr ++;
681
682 if (!*lineptr)
683 continue;
684
685 name = lineptr;
686
687 /*
688 * Search for an instance...
689 */
690
691 while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
692 lineptr ++;
693
694 if (!*lineptr)
695 continue;
696
697 if (*lineptr == '/')
698 {
699 /*
700 * Found an instance...
701 */
702
703 *lineptr++ = '\0';
704 instance = lineptr;
705
706 /*
707 * Search for an instance...
708 */
709
710 while (!isspace(*lineptr & 255) && *lineptr)
711 lineptr ++;
712 }
713 else
714 instance = NULL;
715
716 *lineptr++ = '\0';
717
718 /*
719 * See if the primary instance of the destination exists; if not,
720 * ignore this entry and move on...
721 */
722
723 if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
724 continue;
725
726 /*
727 * Add the destination...
728 */
729
730 num_dests = cupsAddDest(name, instance, num_dests, dests);
731
732 if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
733 {
734 /*
735 * Out of memory!
736 */
737
738 fclose(fp);
739 return (num_dests);
740 }
741
742 /*
743 * Add options until we hit the end of the line...
744 */
745
746 dest->num_options = cupsParseOptions(lineptr, dest->num_options,
747 &(dest->options));
748
749 /*
750 * Set this as default if needed...
751 */
752
753 if (strncasecmp(line, "default", 7) == 0 && printer == NULL)
754 {
755 for (i = 0; i < num_dests; i ++)
756 (*dests)[i].is_default = 0;
757
758 dest->is_default = 1;
759 }
760 }
761
762 /*
763 * Close the file and return...
764 */
765
766 fclose(fp);
767
768 return (num_dests);
769}
770
771
772/*
773 * 'cups_get_sdests()' - Get destinations from a server.
774 */
775
776static int /* O - Number of destinations */
777cups_get_sdests(http_t *http, /* I - HTTP connection */
778 ipp_op_t op, /* I - get-printers or get-classes */
779 int num_dests, /* I - Number of destinations */
780 cups_dest_t **dests) /* IO - Destinations */
781{
fa73b229 782 int i; /* Looping var */
ef416fc2 783 cups_dest_t *dest; /* Current destination */
784 ipp_t *request, /* IPP Request */
785 *response; /* IPP Response */
786 ipp_attribute_t *attr; /* Current attribute */
fa73b229 787 int accepting, /* printer-is-accepting-jobs attribute */
788 shared, /* printer-is-shared attribute */
789 state, /* printer-state attribute */
790 change_time, /* printer-state-change-time attribute */
791 type; /* printer-type attribute */
792 const char *info, /* printer-info attribute */
793 *make_model, /* printer-make-and-model attribute */
794 *name; /* printer-name attribute */
795 char job_sheets[1024], /* job-sheets option */
796 reasons[1024], /* printer-state-reasons attribute */
797 *rptr, /* Pointer into reasons string */
798 temp[255]; /* Temporary string for numbers */
ef416fc2 799 static const char * const pattrs[] = /* Attributes we're interested in */
800 {
fa73b229 801 "job-sheets-default",
802 "printer-info",
803 "printer-is-accepting-jobs",
804 "printer-is-shared",
805 "printer-make-and-model",
ef416fc2 806 "printer-name",
fa73b229 807 "printer-state",
808 "printer-state-change-time",
809 "printer-state-reasons",
810 "printer-type"
ef416fc2 811 };
812
813
814 /*
815 * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
816 * the following attributes:
817 *
818 * attributes-charset
819 * attributes-natural-language
fa73b229 820 * requesting-user-name
ef416fc2 821 */
822
fa73b229 823 request = ippNewRequest(op);
ef416fc2 824
825 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
826 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
827 NULL, pattrs);
828
fa73b229 829 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
830 "requesting-user-name", NULL, cupsUser());
831
ef416fc2 832 /*
833 * Do the request and get back a response...
834 */
835
836 if ((response = cupsDoRequest(http, request, "/")) != NULL)
837 {
838 for (attr = response->attrs; attr != NULL; attr = attr->next)
839 {
840 /*
841 * Skip leading attributes until we hit a printer...
842 */
843
844 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
845 attr = attr->next;
846
847 if (attr == NULL)
848 break;
849
850 /*
851 * Pull the needed attributes from this job...
852 */
853
fa73b229 854 accepting = 0;
855 change_time = 0;
856 info = NULL;
857 make_model = NULL;
858 name = NULL;
859 shared = 1;
860 state = IPP_PRINTER_IDLE;
861 type = CUPS_PRINTER_LOCAL;
ef416fc2 862
863 strcpy(job_sheets, "");
fa73b229 864 strcpy(reasons, "");
ef416fc2 865
866 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
867 {
fa73b229 868 if (!strcmp(attr->name, "job-sheets-default") &&
ef416fc2 869 (attr->value_tag == IPP_TAG_KEYWORD ||
870 attr->value_tag == IPP_TAG_NAME))
871 {
872 if (attr->num_values == 2)
873 snprintf(job_sheets, sizeof(job_sheets), "%s,%s",
874 attr->values[0].string.text, attr->values[1].string.text);
875 else
fa73b229 876 strlcpy(job_sheets, attr->values[0].string.text,
877 sizeof(job_sheets));
ef416fc2 878 }
fa73b229 879 else if (!strcmp(attr->name, "printer-info") &&
880 attr->value_tag == IPP_TAG_TEXT)
881 info = attr->values[0].string.text;
882 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
883 attr->value_tag == IPP_TAG_BOOLEAN)
884 accepting = attr->values[0].boolean;
885 else if (!strcmp(attr->name, "printer-is-shared") &&
886 attr->value_tag == IPP_TAG_BOOLEAN)
887 shared = attr->values[0].boolean;
888 else if (!strcmp(attr->name, "printer-make-and-model") &&
889 attr->value_tag == IPP_TAG_TEXT)
890 make_model = attr->values[0].string.text;
891 else if (!strcmp(attr->name, "printer-name") &&
892 attr->value_tag == IPP_TAG_NAME)
893 name = attr->values[0].string.text;
894 else if (!strcmp(attr->name, "printer-state") &&
895 attr->value_tag == IPP_TAG_ENUM)
896 state = attr->values[0].integer;
897 else if (!strcmp(attr->name, "printer-state-change-time") &&
898 attr->value_tag == IPP_TAG_INTEGER)
899 change_time = attr->values[0].integer;
900 else if (!strcmp(attr->name, "printer-state-reasons") &&
901 attr->value_tag == IPP_TAG_KEYWORD)
902 {
903 strlcpy(reasons, attr->values[0].string.text, sizeof(reasons));
904 for (i = 1, rptr = reasons + strlen(reasons);
905 i < attr->num_values;
906 i ++)
907 {
908 snprintf(rptr, sizeof(reasons) - (rptr - reasons), ",%s",
909 attr->values[i].string.text);
910 rptr += strlen(rptr);
911 }
912 }
913 else if (!strcmp(attr->name, "printer-type") &&
914 attr->value_tag == IPP_TAG_ENUM)
915 type = attr->values[0].integer;
ef416fc2 916
917 attr = attr->next;
918 }
919
920 /*
921 * See if we have everything needed...
922 */
923
924 if (!name)
925 {
926 if (attr == NULL)
927 break;
928 else
929 continue;
930 }
931
932 num_dests = cupsAddDest(name, NULL, num_dests, dests);
933
934 if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL)
fa73b229 935 {
ef416fc2 936 if (job_sheets[0])
fa73b229 937 dest->num_options = cupsAddOption("job-sheets", job_sheets,
938 dest->num_options,
939 &(dest->options));
940
941 if (info)
942 dest->num_options = cupsAddOption("printer-info", info,
943 dest->num_options,
944 &(dest->options));
945
946 sprintf(temp, "%d", accepting);
947 dest->num_options = cupsAddOption("printer-is-accepting-jobs", temp,
948 dest->num_options,
949 &(dest->options));
950
951 sprintf(temp, "%d", shared);
952 dest->num_options = cupsAddOption("printer-is-shared", temp,
953 dest->num_options,
954 &(dest->options));
955
956 if (make_model)
957 dest->num_options = cupsAddOption("printer-make-and-model",
958 make_model, dest->num_options,
ef416fc2 959 &(dest->options));
960
fa73b229 961 sprintf(temp, "%d", state);
962 dest->num_options = cupsAddOption("printer-state", temp,
963 dest->num_options,
964 &(dest->options));
965
966 if (change_time)
967 {
968 sprintf(temp, "%d", change_time);
969 dest->num_options = cupsAddOption("printer-state-change-time", temp,
970 dest->num_options,
971 &(dest->options));
972 }
973
974 if (reasons[0])
975 dest->num_options = cupsAddOption("printer-state-reasons", reasons,
976 dest->num_options,
977 &(dest->options));
978
979 sprintf(temp, "%d", type);
980 dest->num_options = cupsAddOption("printer-type", temp,
981 dest->num_options,
982 &(dest->options));
983 }
984
ef416fc2 985 if (attr == NULL)
986 break;
987 }
988
989 ippDelete(response);
990 }
991
992 /*
993 * Return the count...
994 */
995
996 return (num_dests);
997}
998
999
1000/*
b423cd4c 1001 * End of "$Id: dest.c 5182 2006-02-26 04:10:27Z mike $".
ef416fc2 1002 */