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