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