]> 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/*
2abf387c 2 * "$Id: dest.c 6044 2006-10-17 20:32:59Z 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 *
2abf387c 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.
ef416fc2 77 */
78
79int /* O - New number of destinations */
2abf387c 80cupsAddDest(const char *name, /* I - Destination name */
81 const char *instance, /* I - Instance name or NULL for none/primary */
ef416fc2 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 */
2abf387c 87 cups_dest_t *parent; /* Parent destination */
88 cups_option_t *option; /* Current option */
ef416fc2 89
90
2abf387c 91 if (!name || !dests)
ef416fc2 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
2abf387c 111 /*
112 * Find where to insert the destination...
113 */
114
ef416fc2 115 for (i = num_dests; i > 0; i --, dest ++)
116 if (strcasecmp(name, dest->name) < 0)
117 break;
2abf387c 118 else if (!instance && dest->instance)
119 break;
b423cd4c 120 else if (!strcasecmp(name, dest->name) &&
2abf387c 121 instance && dest->instance &&
ef416fc2 122 strcasecmp(instance, dest->instance) < 0)
123 break;
124
125 if (i > 0)
126 memmove(dest + 1, dest, i * sizeof(cups_dest_t));
127
2abf387c 128 /*
129 * Initialize the destination...
130 */
131
ef416fc2 132 dest->name = strdup(name);
133 dest->is_default = 0;
134 dest->num_options = 0;
135 dest->options = (cups_option_t *)0;
136
2abf387c 137 if (!instance)
ef416fc2 138 dest->instance = NULL;
139 else
2abf387c 140 {
141 /*
142 * Copy options from the primary instance...
143 */
144
ef416fc2 145 dest->instance = strdup(instance);
146
2abf387c 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
ef416fc2 158 return (num_dests + 1);
159}
160
161
162/*
163 * 'cupsFreeDests()' - Free the memory used by the list of destinations.
164 */
165
166void
167cupsFreeDests(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
198cups_dest_t * /* O - Destination pointer or NULL */
2abf387c 199cupsGetDest(const char *name, /* I - Destination name or NULL for the default destination */
200 const char *instance, /* I - Instance name or NULL */
ef416fc2 201 int num_dests, /* I - Number of destinations */
202 cups_dest_t *dests) /* I - Destinations */
203{
204 int comp; /* Result of comparison */
205
206
2abf387c 207 if (num_dests <= 0 || !dests)
ef416fc2 208 return (NULL);
209
2abf387c 210 if (!name)
ef416fc2 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 {
2abf387c 237 if ((!instance && !dests->instance) ||
ef416fc2 238 (instance != NULL && dests->instance != NULL &&
2abf387c 239 !strcasecmp(instance, dests->instance)))
ef416fc2 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.
ecdc0628 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.
2abf387c 259 *
260 * Use the cupsFreeDests() function to free the destination list and
261 * the cupsGetDest() function to find a particular destination.
ef416fc2 262 */
263
264int /* O - Number of destinations */
265cupsGetDests(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 *
ecdc0628 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 *
2abf387c 294 * Use the cupsFreeDests() function to free the destination list and
295 * the cupsGetDest() function to find a particular destination.
296 *
ef416fc2 297 * @since CUPS 1.1.21@
298 */
299
300int /* O - Number of destinations */
301cupsGetDests2(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 */
b423cd4c 308 char filename[1024]; /* Local ~/.cups/lpoptions file */
ef416fc2 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 /*
b423cd4c 391 * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
ef416fc2 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 {
b423cd4c 399 snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
400 if (access(filename, 0))
401 snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
402
ef416fc2 403 num_dests = cups_get_dests(filename, num_dests, dests);
404 }
405
406 /*
407 * Validate the current default destination - this prevents old
b423cd4c 408 * Default lines in /etc/cups/lpoptions and ~/.cups/lpoptions from
ef416fc2 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
b423cd4c 460 * as root and ~/.cups/lpoptions when run as a normal user.
ef416fc2 461 */
462
463void
464cupsSetDests(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
b423cd4c 487 * as root and ~/.cups/lpoptions when run as a normal user.
ef416fc2 488 *
489 * @since CUPS 1.1.21@
490 */
491
492int /* O - 0 on success, -1 on error */
493cupsSetDests2(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 */
8ca02f3c 501 _ipp_option_t *match; /* Matching attribute for option */
ef416fc2 502 FILE *fp; /* File pointer */
503 const char *home; /* HOME environment variable */
504 char filename[1024]; /* lpoptions file */
505 int num_temps; /* Number of temporary destinations */
506 cups_dest_t *temps, /* Temporary destinations */
507 *temp; /* Current temporary dest */
508 const char *val; /* Value of temporary option */
509 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
510
511
512 /*
513 * Range check the input...
514 */
515
516 if (!http || !num_dests || !dests)
517 return (-1);
518
519 /*
520 * Get the server destinations...
521 */
522
523 num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, 0, &temps);
524 num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, num_temps, &temps);
525
526 /*
527 * Figure out which file to write to...
528 */
529
530 snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
531
532#ifndef WIN32
533 if (getuid())
534 {
535 /*
536 * Merge in server defaults...
537 */
538
539 num_temps = cups_get_dests(filename, num_temps, &temps);
540
541 /*
542 * Point to user defaults...
543 */
544
545 if ((home = getenv("HOME")) != NULL)
b423cd4c 546 {
547 /*
548 * Remove the old ~/.lpoptions file...
549 */
550
ef416fc2 551 snprintf(filename, sizeof(filename), "%s/.lpoptions", home);
b423cd4c 552 unlink(filename);
553
554 /*
555 * Create ~/.cups subdirectory...
556 */
557
558 snprintf(filename, sizeof(filename), "%s/.cups", home);
559 if (access(filename, 0))
560 mkdir(filename, 0700);
561
562 snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
563 }
ef416fc2 564 }
565#endif /* !WIN32 */
566
567 /*
568 * Try to open the file...
569 */
570
571 if ((fp = fopen(filename, "w")) == NULL)
572 {
573 cupsFreeDests(num_temps, temps);
574 return (-1);
575 }
576
d6ae789d 577#ifndef WIN32
578 /*
579 * Set the permissions to 0644 when saving to the /etc/cups/lpoptions
580 * file...
581 */
582
583 if (!getuid())
584 fchmod(fileno(fp), 0644);
585#endif /* !WIN32 */
586
ef416fc2 587 /*
588 * Write each printer; each line looks like:
589 *
590 * Dest name[/instance] options
591 * Default name[/instance] options
592 */
593
594 for (i = num_dests, dest = dests; i > 0; i --, dest ++)
595 if (dest->instance != NULL || dest->num_options != 0 || dest->is_default)
596 {
597 if (dest->is_default)
598 {
599 fprintf(fp, "Default %s", dest->name);
600 if (dest->instance)
601 fprintf(fp, "/%s", dest->instance);
602
603 wrote = 1;
604 }
605 else
606 wrote = 0;
607
608 if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL)
609 temp = cupsGetDest(dest->name, NULL, num_temps, temps);
610
611 for (j = dest->num_options, option = dest->options; j > 0; j --, option ++)
612 {
8ca02f3c 613 /*
614 * See if this option is a printer attribute; if so, skip it...
615 */
616
617 if ((match = _ippFindOption(option->name)) != NULL &&
618 match->group_tag == IPP_TAG_PRINTER)
619 continue;
620
ef416fc2 621 /*
622 * See if the server/global options match these; if so, don't
623 * write 'em.
624 */
625
8ca02f3c 626 if (temp &&
627 (val = cupsGetOption(option->name, temp->num_options,
628 temp->options)) != NULL &&
629 !strcasecmp(val, option->value))
630 continue;
ef416fc2 631
632 /*
633 * Options don't match, write to the file...
634 */
635
636 if (!wrote)
637 {
638 fprintf(fp, "Dest %s", dest->name);
639 if (dest->instance)
640 fprintf(fp, "/%s", dest->instance);
641 wrote = 1;
642 }
643
644 if (option->value[0])
645 {
8ca02f3c 646 if (strchr(option->value, ' ') ||
647 strchr(option->value, '\\') ||
648 strchr(option->value, '\"') ||
649 strchr(option->value, '\''))
650 {
651 /*
652 * Quote the value...
653 */
654
655 fprintf(fp, " %s=\"", option->name);
656
657 for (val = option->value; *val; val ++)
658 {
659 if (strchr("\"\'\\", *val))
660 putc('\\', fp);
661
662 putc(*val, fp);
663 }
664
665 putc('\"', fp);
666 }
667 else
668 {
669 /*
670 * Store the literal value...
671 */
672
ef416fc2 673 fprintf(fp, " %s=%s", option->name, option->value);
8ca02f3c 674 }
ef416fc2 675 }
676 else
677 fprintf(fp, " %s", option->name);
678 }
679
680 if (wrote)
681 fputs("\n", fp);
682 }
683
684 /*
fa73b229 685 * Free the temporary destinations and close the file...
ef416fc2 686 */
687
688 cupsFreeDests(num_temps, temps);
689
fa73b229 690 fclose(fp);
691
692#ifdef HAVE_NOTIFY_POST
ef416fc2 693 /*
fa73b229 694 * Send a notification so that MacOS X applications can know about the
695 * change, too.
ef416fc2 696 */
697
fa73b229 698 notify_post("com.apple.printerListChange");
699#endif /* HAVE_NOTIFY_POST */
ef416fc2 700
701 return (0);
702}
703
704
705/*
706 * 'cups_get_dests()' - Get destinations from a file.
707 */
708
709static int /* O - Number of destinations */
710cups_get_dests(const char *filename, /* I - File to read from */
711 int num_dests, /* I - Number of destinations */
712 cups_dest_t **dests) /* IO - Destinations */
713{
714 int i; /* Looping var */
715 cups_dest_t *dest; /* Current destination */
716 FILE *fp; /* File pointer */
717 char line[8192], /* Line from file */
718 *lineptr, /* Pointer into line */
719 *name, /* Name of destination/option */
720 *instance; /* Instance of destination */
721 const char *printer; /* PRINTER or LPDEST */
722
723
724 /*
725 * Check environment variables...
726 */
727
728 if ((printer = getenv("LPDEST")) == NULL)
729 if ((printer = getenv("PRINTER")) != NULL)
730 if (strcmp(printer, "lp") == 0)
731 printer = NULL;
732
733 /*
734 * Try to open the file...
735 */
736
737 if ((fp = fopen(filename, "r")) == NULL)
738 return (num_dests);
739
740 /*
741 * Read each printer; each line looks like:
742 *
743 * Dest name[/instance] options
744 * Default name[/instance] options
745 */
746
747 while (fgets(line, sizeof(line), fp) != NULL)
748 {
749 /*
750 * See what type of line it is...
751 */
752
753 if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4] & 255))
754 lineptr = line + 4;
755 else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255))
756 lineptr = line + 7;
757 else
758 continue;
759
760 /*
761 * Skip leading whitespace...
762 */
763
764 while (isspace(*lineptr & 255))
765 lineptr ++;
766
767 if (!*lineptr)
768 continue;
769
770 name = lineptr;
771
772 /*
773 * Search for an instance...
774 */
775
776 while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/')
777 lineptr ++;
778
779 if (!*lineptr)
780 continue;
781
782 if (*lineptr == '/')
783 {
784 /*
785 * Found an instance...
786 */
787
788 *lineptr++ = '\0';
789 instance = lineptr;
790
791 /*
792 * Search for an instance...
793 */
794
795 while (!isspace(*lineptr & 255) && *lineptr)
796 lineptr ++;
797 }
798 else
799 instance = NULL;
800
801 *lineptr++ = '\0';
802
803 /*
804 * See if the primary instance of the destination exists; if not,
805 * ignore this entry and move on...
806 */
807
808 if (cupsGetDest(name, NULL, num_dests, *dests) == NULL)
809 continue;
810
811 /*
812 * Add the destination...
813 */
814
815 num_dests = cupsAddDest(name, instance, num_dests, dests);
816
817 if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL)
818 {
819 /*
820 * Out of memory!
821 */
822
823 fclose(fp);
824 return (num_dests);
825 }
826
827 /*
828 * Add options until we hit the end of the line...
829 */
830
831 dest->num_options = cupsParseOptions(lineptr, dest->num_options,
832 &(dest->options));
833
834 /*
835 * Set this as default if needed...
836 */
837
838 if (strncasecmp(line, "default", 7) == 0 && printer == NULL)
839 {
840 for (i = 0; i < num_dests; i ++)
841 (*dests)[i].is_default = 0;
842
843 dest->is_default = 1;
844 }
845 }
846
847 /*
848 * Close the file and return...
849 */
850
851 fclose(fp);
852
853 return (num_dests);
854}
855
856
857/*
858 * 'cups_get_sdests()' - Get destinations from a server.
859 */
860
861static int /* O - Number of destinations */
862cups_get_sdests(http_t *http, /* I - HTTP connection */
863 ipp_op_t op, /* I - get-printers or get-classes */
864 int num_dests, /* I - Number of destinations */
865 cups_dest_t **dests) /* IO - Destinations */
866{
fa73b229 867 int i; /* Looping var */
ef416fc2 868 cups_dest_t *dest; /* Current destination */
869 ipp_t *request, /* IPP Request */
870 *response; /* IPP Response */
871 ipp_attribute_t *attr; /* Current attribute */
fa73b229 872 int accepting, /* printer-is-accepting-jobs attribute */
873 shared, /* printer-is-shared attribute */
874 state, /* printer-state attribute */
875 change_time, /* printer-state-change-time attribute */
876 type; /* printer-type attribute */
877 const char *info, /* printer-info attribute */
878 *make_model, /* printer-make-and-model attribute */
879 *name; /* printer-name attribute */
880 char job_sheets[1024], /* job-sheets option */
881 reasons[1024], /* printer-state-reasons attribute */
882 *rptr, /* Pointer into reasons string */
883 temp[255]; /* Temporary string for numbers */
ef416fc2 884 static const char * const pattrs[] = /* Attributes we're interested in */
885 {
fa73b229 886 "job-sheets-default",
887 "printer-info",
888 "printer-is-accepting-jobs",
889 "printer-is-shared",
890 "printer-make-and-model",
ef416fc2 891 "printer-name",
fa73b229 892 "printer-state",
893 "printer-state-change-time",
894 "printer-state-reasons",
895 "printer-type"
ef416fc2 896 };
897
898
899 /*
900 * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
901 * the following attributes:
902 *
903 * attributes-charset
904 * attributes-natural-language
fa73b229 905 * requesting-user-name
ef416fc2 906 */
907
fa73b229 908 request = ippNewRequest(op);
ef416fc2 909
910 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
911 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
912 NULL, pattrs);
913
fa73b229 914 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
915 "requesting-user-name", NULL, cupsUser());
916
ef416fc2 917 /*
918 * Do the request and get back a response...
919 */
920
921 if ((response = cupsDoRequest(http, request, "/")) != NULL)
922 {
923 for (attr = response->attrs; attr != NULL; attr = attr->next)
924 {
925 /*
926 * Skip leading attributes until we hit a printer...
927 */
928
929 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
930 attr = attr->next;
931
932 if (attr == NULL)
933 break;
934
935 /*
936 * Pull the needed attributes from this job...
937 */
938
fa73b229 939 accepting = 0;
940 change_time = 0;
941 info = NULL;
942 make_model = NULL;
943 name = NULL;
944 shared = 1;
945 state = IPP_PRINTER_IDLE;
946 type = CUPS_PRINTER_LOCAL;
ef416fc2 947
948 strcpy(job_sheets, "");
fa73b229 949 strcpy(reasons, "");
ef416fc2 950
951 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
952 {
fa73b229 953 if (!strcmp(attr->name, "job-sheets-default") &&
ef416fc2 954 (attr->value_tag == IPP_TAG_KEYWORD ||
955 attr->value_tag == IPP_TAG_NAME))
956 {
957 if (attr->num_values == 2)
958 snprintf(job_sheets, sizeof(job_sheets), "%s,%s",
959 attr->values[0].string.text, attr->values[1].string.text);
960 else
fa73b229 961 strlcpy(job_sheets, attr->values[0].string.text,
962 sizeof(job_sheets));
ef416fc2 963 }
fa73b229 964 else if (!strcmp(attr->name, "printer-info") &&
965 attr->value_tag == IPP_TAG_TEXT)
966 info = attr->values[0].string.text;
967 else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
968 attr->value_tag == IPP_TAG_BOOLEAN)
969 accepting = attr->values[0].boolean;
970 else if (!strcmp(attr->name, "printer-is-shared") &&
971 attr->value_tag == IPP_TAG_BOOLEAN)
972 shared = attr->values[0].boolean;
973 else if (!strcmp(attr->name, "printer-make-and-model") &&
974 attr->value_tag == IPP_TAG_TEXT)
975 make_model = attr->values[0].string.text;
976 else if (!strcmp(attr->name, "printer-name") &&
977 attr->value_tag == IPP_TAG_NAME)
978 name = attr->values[0].string.text;
979 else if (!strcmp(attr->name, "printer-state") &&
980 attr->value_tag == IPP_TAG_ENUM)
981 state = attr->values[0].integer;
982 else if (!strcmp(attr->name, "printer-state-change-time") &&
983 attr->value_tag == IPP_TAG_INTEGER)
984 change_time = attr->values[0].integer;
985 else if (!strcmp(attr->name, "printer-state-reasons") &&
986 attr->value_tag == IPP_TAG_KEYWORD)
987 {
988 strlcpy(reasons, attr->values[0].string.text, sizeof(reasons));
989 for (i = 1, rptr = reasons + strlen(reasons);
990 i < attr->num_values;
991 i ++)
992 {
993 snprintf(rptr, sizeof(reasons) - (rptr - reasons), ",%s",
994 attr->values[i].string.text);
995 rptr += strlen(rptr);
996 }
997 }
998 else if (!strcmp(attr->name, "printer-type") &&
999 attr->value_tag == IPP_TAG_ENUM)
1000 type = attr->values[0].integer;
ef416fc2 1001
1002 attr = attr->next;
1003 }
1004
1005 /*
1006 * See if we have everything needed...
1007 */
1008
1009 if (!name)
1010 {
1011 if (attr == NULL)
1012 break;
1013 else
1014 continue;
1015 }
1016
1017 num_dests = cupsAddDest(name, NULL, num_dests, dests);
1018
1019 if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL)
fa73b229 1020 {
ef416fc2 1021 if (job_sheets[0])
fa73b229 1022 dest->num_options = cupsAddOption("job-sheets", job_sheets,
1023 dest->num_options,
1024 &(dest->options));
1025
1026 if (info)
1027 dest->num_options = cupsAddOption("printer-info", info,
1028 dest->num_options,
1029 &(dest->options));
1030
1031 sprintf(temp, "%d", accepting);
1032 dest->num_options = cupsAddOption("printer-is-accepting-jobs", temp,
1033 dest->num_options,
1034 &(dest->options));
1035
1036 sprintf(temp, "%d", shared);
1037 dest->num_options = cupsAddOption("printer-is-shared", temp,
1038 dest->num_options,
1039 &(dest->options));
1040
1041 if (make_model)
1042 dest->num_options = cupsAddOption("printer-make-and-model",
1043 make_model, dest->num_options,
ef416fc2 1044 &(dest->options));
1045
fa73b229 1046 sprintf(temp, "%d", state);
1047 dest->num_options = cupsAddOption("printer-state", temp,
1048 dest->num_options,
1049 &(dest->options));
1050
1051 if (change_time)
1052 {
1053 sprintf(temp, "%d", change_time);
1054 dest->num_options = cupsAddOption("printer-state-change-time", temp,
1055 dest->num_options,
1056 &(dest->options));
1057 }
1058
1059 if (reasons[0])
1060 dest->num_options = cupsAddOption("printer-state-reasons", reasons,
1061 dest->num_options,
1062 &(dest->options));
1063
1064 sprintf(temp, "%d", type);
1065 dest->num_options = cupsAddOption("printer-type", temp,
1066 dest->num_options,
1067 &(dest->options));
1068 }
1069
ef416fc2 1070 if (attr == NULL)
1071 break;
1072 }
1073
1074 ippDelete(response);
1075 }
1076
1077 /*
1078 * Return the count...
1079 */
1080
1081 return (num_dests);
1082}
1083
1084
1085/*
2abf387c 1086 * End of "$Id: dest.c 6044 2006-10-17 20:32:59Z mike $".
ef416fc2 1087 */