]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
2 | * "$Id: dest.c 4918 2006-01-12 05:14:40Z mike $" | |
3 | * | |
4 | * User-defined destination (and option) support for the Common UNIX | |
5 | * Printing System (CUPS). | |
6 | * | |
7 | * Copyright 1997-2006 by Easy Software Products. | |
8 | * | |
9 | * These coded instructions, statements, and computer programs are the | |
10 | * property of Easy Software Products and are protected by Federal | |
11 | * copyright law. Distribution and use rights are outlined in the file | |
12 | * "LICENSE.txt" which should have been included with this file. If this | |
13 | * file is missing or damaged please contact Easy Software Products | |
14 | * at: | |
15 | * | |
16 | * Attn: CUPS Licensing Information | |
17 | * Easy Software Products | |
18 | * 44141 Airport View Drive, Suite 204 | |
19 | * Hollywood, Maryland 20636 USA | |
20 | * | |
21 | * Voice: (301) 373-9600 | |
22 | * EMail: cups-info@cups.org | |
23 | * WWW: http://www.cups.org | |
24 | * | |
25 | * This file is subject to the Apple OS-Developed Software exception. | |
26 | * | |
27 | * Contents: | |
28 | * | |
29 | * cupsAddDest() - Add a destination to the list of destinations. | |
30 | * cupsFreeDests() - Free the memory used by the list of destinations. | |
31 | * cupsGetDest() - Get the named destination from the list. | |
32 | * cupsGetDests() - Get the list of destinations from the default server. | |
33 | * cupsGetDests2() - Get the list of destinations from the specified server. | |
34 | * cupsSetDests() - Set the list of destinations for the default server. | |
35 | * cupsSetDests2() - Set the list of destinations for the specified server. | |
36 | * cups_get_dests() - Get destinations from a file. | |
37 | * cups_get_sdests() - Get destinations from a server. | |
38 | */ | |
39 | ||
40 | /* | |
41 | * Include necessary headers... | |
42 | */ | |
43 | ||
44 | #include "globals.h" | |
45 | #include <stdlib.h> | |
46 | #include <ctype.h> | |
47 | ||
48 | ||
49 | /* | |
50 | * Local functions... | |
51 | */ | |
52 | ||
53 | static int cups_get_dests(const char *filename, int num_dests, | |
54 | cups_dest_t **dests); | |
55 | static int cups_get_sdests(http_t *http, ipp_op_t op, int num_dests, | |
56 | cups_dest_t **dests); | |
57 | ||
58 | ||
59 | /* | |
60 | * 'cupsAddDest()' - Add a destination to the list of destinations. | |
61 | * | |
62 | * Use the cupsSaveDests() function to save the updated list of destinations | |
63 | * to the user's lpoptions file. | |
64 | */ | |
65 | ||
66 | int /* O - New number of destinations */ | |
67 | cupsAddDest(const char *name, /* I - Name of destination */ | |
68 | const char *instance, /* I - Instance of destination or NULL for none/primary */ | |
69 | int num_dests, /* I - Number of destinations */ | |
70 | cups_dest_t **dests) /* IO - Destinations */ | |
71 | { | |
72 | int i; /* Looping var */ | |
73 | cups_dest_t *dest; /* Destination pointer */ | |
74 | ||
75 | ||
76 | if (name == NULL || dests == NULL) | |
77 | return (0); | |
78 | ||
79 | if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL) | |
80 | return (num_dests); | |
81 | ||
82 | /* | |
83 | * Add new destination... | |
84 | */ | |
85 | ||
86 | if (num_dests == 0) | |
87 | dest = malloc(sizeof(cups_dest_t)); | |
88 | else | |
89 | dest = realloc(*dests, sizeof(cups_dest_t) * (num_dests + 1)); | |
90 | ||
91 | if (dest == NULL) | |
92 | return (num_dests); | |
93 | ||
94 | *dests = dest; | |
95 | ||
96 | for (i = num_dests; i > 0; i --, dest ++) | |
97 | if (strcasecmp(name, dest->name) < 0) | |
98 | break; | |
99 | else if (strcasecmp(name, dest->name) == 0 && | |
100 | instance != NULL && dest->instance != NULL && | |
101 | strcasecmp(instance, dest->instance) < 0) | |
102 | break; | |
103 | ||
104 | if (i > 0) | |
105 | memmove(dest + 1, dest, i * sizeof(cups_dest_t)); | |
106 | ||
107 | dest->name = strdup(name); | |
108 | dest->is_default = 0; | |
109 | dest->num_options = 0; | |
110 | dest->options = (cups_option_t *)0; | |
111 | ||
112 | if (instance == NULL) | |
113 | dest->instance = NULL; | |
114 | else | |
115 | dest->instance = strdup(instance); | |
116 | ||
117 | return (num_dests + 1); | |
118 | } | |
119 | ||
120 | ||
121 | /* | |
122 | * 'cupsFreeDests()' - Free the memory used by the list of destinations. | |
123 | */ | |
124 | ||
125 | void | |
126 | cupsFreeDests(int num_dests, /* I - Number of destinations */ | |
127 | cups_dest_t *dests) /* I - Destinations */ | |
128 | { | |
129 | int i; /* Looping var */ | |
130 | cups_dest_t *dest; /* Current destination */ | |
131 | ||
132 | ||
133 | if (num_dests == 0 || dests == NULL) | |
134 | return; | |
135 | ||
136 | for (i = num_dests, dest = dests; i > 0; i --, dest ++) | |
137 | { | |
138 | free(dest->name); | |
139 | ||
140 | if (dest->instance) | |
141 | free(dest->instance); | |
142 | ||
143 | cupsFreeOptions(dest->num_options, dest->options); | |
144 | } | |
145 | ||
146 | free(dests); | |
147 | } | |
148 | ||
149 | ||
150 | /* | |
151 | * 'cupsGetDest()' - Get the named destination from the list. | |
152 | * | |
153 | * Use the cupsGetDests() or cupsGetDests2() functions to get a | |
154 | * list of supported destinations for the current user. | |
155 | */ | |
156 | ||
157 | cups_dest_t * /* O - Destination pointer or NULL */ | |
158 | cupsGetDest(const char *name, /* I - Name of destination */ | |
159 | const char *instance, /* I - Instance of destination */ | |
160 | int num_dests, /* I - Number of destinations */ | |
161 | cups_dest_t *dests) /* I - Destinations */ | |
162 | { | |
163 | int comp; /* Result of comparison */ | |
164 | ||
165 | ||
166 | if (num_dests == 0 || dests == NULL) | |
167 | return (NULL); | |
168 | ||
169 | if (name == NULL) | |
170 | { | |
171 | /* | |
172 | * NULL name for default printer. | |
173 | */ | |
174 | ||
175 | while (num_dests > 0) | |
176 | { | |
177 | if (dests->is_default) | |
178 | return (dests); | |
179 | ||
180 | num_dests --; | |
181 | dests ++; | |
182 | } | |
183 | } | |
184 | else | |
185 | { | |
186 | /* | |
187 | * Lookup name and optionally the instance... | |
188 | */ | |
189 | ||
190 | while (num_dests > 0) | |
191 | { | |
192 | if ((comp = strcasecmp(name, dests->name)) < 0) | |
193 | return (NULL); | |
194 | else if (comp == 0) | |
195 | { | |
196 | if ((instance == NULL && dests->instance == NULL) || | |
197 | (instance != NULL && dests->instance != NULL && | |
198 | strcasecmp(instance, dests->instance) == 0)) | |
199 | return (dests); | |
200 | } | |
201 | ||
202 | num_dests --; | |
203 | dests ++; | |
204 | } | |
205 | } | |
206 | ||
207 | return (NULL); | |
208 | } | |
209 | ||
210 | ||
211 | /* | |
212 | * 'cupsGetDests()' - Get the list of destinations from the default server. | |
213 | */ | |
214 | ||
215 | int /* O - Number of destinations */ | |
216 | cupsGetDests(cups_dest_t **dests) /* O - Destinations */ | |
217 | { | |
218 | int num_dests; /* Number of destinations */ | |
219 | http_t *http; /* HTTP connection */ | |
220 | ||
221 | ||
222 | /* | |
223 | * Connect to the CUPS server and get the destination list and options... | |
224 | */ | |
225 | ||
226 | http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); | |
227 | ||
228 | num_dests = cupsGetDests2(http, dests); | |
229 | ||
230 | if (http) | |
231 | httpClose(http); | |
232 | ||
233 | return (num_dests); | |
234 | } | |
235 | ||
236 | ||
237 | /* | |
238 | * 'cupsGetDests2()' - Get the list of destinations from the specified server. | |
239 | * | |
240 | * @since CUPS 1.1.21@ | |
241 | */ | |
242 | ||
243 | int /* O - Number of destinations */ | |
244 | cupsGetDests2(http_t *http, /* I - HTTP connection */ | |
245 | cups_dest_t **dests) /* O - Destinations */ | |
246 | { | |
247 | int i; /* Looping var */ | |
248 | int num_dests; /* Number of destinations */ | |
249 | cups_dest_t *dest; /* Destination pointer */ | |
250 | const char *home; /* HOME environment variable */ | |
251 | char filename[1024]; /* Local ~/.lpoptions file */ | |
252 | const char *defprinter; /* Default printer */ | |
253 | char name[1024], /* Copy of printer name */ | |
254 | *instance; /* Pointer to instance name */ | |
255 | int num_reals; /* Number of real queues */ | |
256 | cups_dest_t *reals; /* Real queues */ | |
257 | _cups_globals_t *cg = _cupsGlobals(); /* Global data */ | |
258 | ||
259 | ||
260 | /* | |
261 | * Range check the input... | |
262 | */ | |
263 | ||
264 | if (!http || !dests) | |
265 | return (0); | |
266 | ||
267 | /* | |
268 | * Initialize destination array... | |
269 | */ | |
270 | ||
271 | num_dests = 0; | |
272 | *dests = (cups_dest_t *)0; | |
273 | ||
274 | /* | |
275 | * Grab the printers and classes... | |
276 | */ | |
277 | ||
278 | num_dests = cups_get_sdests(http, CUPS_GET_PRINTERS, num_dests, dests); | |
279 | num_dests = cups_get_sdests(http, CUPS_GET_CLASSES, num_dests, dests); | |
280 | ||
281 | /* | |
282 | * Make a copy of the "real" queues for a later sanity check... | |
283 | */ | |
284 | ||
285 | if (num_dests > 0) | |
286 | { | |
287 | num_reals = num_dests; | |
288 | reals = calloc(num_reals, sizeof(cups_dest_t)); | |
289 | ||
290 | if (reals) | |
291 | memcpy(reals, *dests, num_reals * sizeof(cups_dest_t)); | |
292 | else | |
293 | num_reals = 0; | |
294 | } | |
295 | else | |
296 | { | |
297 | num_reals = 0; | |
298 | reals = NULL; | |
299 | } | |
300 | ||
301 | /* | |
302 | * Grab the default destination... | |
303 | */ | |
304 | ||
305 | if ((defprinter = cupsGetDefault2(http)) != NULL) | |
306 | { | |
307 | /* | |
308 | * Grab printer and instance name... | |
309 | */ | |
310 | ||
311 | strlcpy(name, defprinter, sizeof(name)); | |
312 | ||
313 | if ((instance = strchr(name, '/')) != NULL) | |
314 | *instance++ = '\0'; | |
315 | ||
316 | /* | |
317 | * Lookup the printer and instance and make it the default... | |
318 | */ | |
319 | ||
320 | if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL) | |
321 | dest->is_default = 1; | |
322 | } | |
323 | else | |
324 | { | |
325 | /* | |
326 | * This initialization of "instance" is unnecessary, but avoids a | |
327 | * compiler warning... | |
328 | */ | |
329 | ||
330 | instance = NULL; | |
331 | } | |
332 | ||
333 | /* | |
334 | * Load the /etc/cups/lpoptions and ~/.lpoptions files... | |
335 | */ | |
336 | ||
337 | snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); | |
338 | num_dests = cups_get_dests(filename, num_dests, dests); | |
339 | ||
340 | if ((home = getenv("HOME")) != NULL) | |
341 | { | |
342 | snprintf(filename, sizeof(filename), "%s/.lpoptions", home); | |
343 | num_dests = cups_get_dests(filename, num_dests, dests); | |
344 | } | |
345 | ||
346 | /* | |
347 | * Validate the current default destination - this prevents old | |
348 | * Default lines in /etc/cups/lpoptions and ~/.lpoptions from | |
349 | * pointing to a non-existent printer or class... | |
350 | */ | |
351 | ||
352 | if (num_reals) | |
353 | { | |
354 | /* | |
355 | * See if we have a default printer... | |
356 | */ | |
357 | ||
358 | if ((dest = cupsGetDest(NULL, NULL, num_dests, *dests)) != NULL) | |
359 | { | |
360 | /* | |
361 | * Have a default; see if it is real... | |
362 | */ | |
363 | ||
364 | dest = cupsGetDest(dest->name, NULL, num_reals, reals); | |
365 | } | |
366 | ||
367 | /* | |
368 | * If dest is NULL, then no default (that exists) is set, so we | |
369 | * need to set a default if one exists... | |
370 | */ | |
371 | ||
372 | if (dest == NULL && defprinter != NULL) | |
373 | { | |
374 | for (i = 0; i < num_dests; i ++) | |
375 | (*dests)[i].is_default = 0; | |
376 | ||
377 | if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL) | |
378 | dest->is_default = 1; | |
379 | } | |
380 | ||
381 | /* | |
382 | * Free memory... | |
383 | */ | |
384 | ||
385 | free(reals); | |
386 | } | |
387 | ||
388 | /* | |
389 | * Return the number of destinations... | |
390 | */ | |
391 | ||
392 | return (num_dests); | |
393 | } | |
394 | ||
395 | ||
396 | /* | |
397 | * 'cupsSetDests()' - Save the list of destinations for the default server. | |
398 | * | |
399 | * This function saves the destinations to /etc/cups/lpoptions when run | |
400 | * as root and ~/.lpoptions when run as a normal user. | |
401 | */ | |
402 | ||
403 | void | |
404 | cupsSetDests(int num_dests, /* I - Number of destinations */ | |
405 | cups_dest_t *dests) /* I - Destinations */ | |
406 | { | |
407 | http_t *http; /* HTTP connection */ | |
408 | ||
409 | ||
410 | /* | |
411 | * Connect to the CUPS server and save the destination list and options... | |
412 | */ | |
413 | ||
414 | http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); | |
415 | ||
416 | cupsSetDests2(http, num_dests, dests); | |
417 | ||
418 | if (http) | |
419 | httpClose(http); | |
420 | } | |
421 | ||
422 | ||
423 | /* | |
424 | * 'cupsSetDests2()' - Save the list of destinations for the specified server. | |
425 | * | |
426 | * This function saves the destinations to /etc/cups/lpoptions when run | |
427 | * as root and ~/.lpoptions when run as a normal user. | |
428 | * | |
429 | * @since CUPS 1.1.21@ | |
430 | */ | |
431 | ||
432 | int /* O - 0 on success, -1 on error */ | |
433 | cupsSetDests2(http_t *http, /* I - HTTP connection */ | |
434 | int num_dests, /* I - Number of destinations */ | |
435 | cups_dest_t *dests) /* I - Destinations */ | |
436 | { | |
437 | int i, j; /* Looping vars */ | |
438 | int wrote; /* Wrote definition? */ | |
439 | cups_dest_t *dest; /* Current destination */ | |
440 | cups_option_t *option; /* Current option */ | |
441 | FILE *fp; /* File pointer */ | |
442 | const char *home; /* HOME environment variable */ | |
443 | char filename[1024]; /* lpoptions file */ | |
444 | int num_temps; /* Number of temporary destinations */ | |
445 | cups_dest_t *temps, /* Temporary destinations */ | |
446 | *temp; /* Current temporary dest */ | |
447 | const char *val; /* Value of temporary option */ | |
448 | _cups_globals_t *cg = _cupsGlobals(); /* Global data */ | |
449 | ||
450 | ||
451 | /* | |
452 | * Range check the input... | |
453 | */ | |
454 | ||
455 | if (!http || !num_dests || !dests) | |
456 | return (-1); | |
457 | ||
458 | /* | |
459 | * Get the server destinations... | |
460 | */ | |
461 | ||
462 | num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, 0, &temps); | |
463 | num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, num_temps, &temps); | |
464 | ||
465 | /* | |
466 | * Figure out which file to write to... | |
467 | */ | |
468 | ||
469 | snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); | |
470 | ||
471 | #ifndef WIN32 | |
472 | if (getuid()) | |
473 | { | |
474 | /* | |
475 | * Merge in server defaults... | |
476 | */ | |
477 | ||
478 | num_temps = cups_get_dests(filename, num_temps, &temps); | |
479 | ||
480 | /* | |
481 | * Point to user defaults... | |
482 | */ | |
483 | ||
484 | if ((home = getenv("HOME")) != NULL) | |
485 | snprintf(filename, sizeof(filename), "%s/.lpoptions", home); | |
486 | } | |
487 | #endif /* !WIN32 */ | |
488 | ||
489 | /* | |
490 | * Try to open the file... | |
491 | */ | |
492 | ||
493 | if ((fp = fopen(filename, "w")) == NULL) | |
494 | { | |
495 | cupsFreeDests(num_temps, temps); | |
496 | return (-1); | |
497 | } | |
498 | ||
499 | /* | |
500 | * Write each printer; each line looks like: | |
501 | * | |
502 | * Dest name[/instance] options | |
503 | * Default name[/instance] options | |
504 | */ | |
505 | ||
506 | for (i = num_dests, dest = dests; i > 0; i --, dest ++) | |
507 | if (dest->instance != NULL || dest->num_options != 0 || dest->is_default) | |
508 | { | |
509 | if (dest->is_default) | |
510 | { | |
511 | fprintf(fp, "Default %s", dest->name); | |
512 | if (dest->instance) | |
513 | fprintf(fp, "/%s", dest->instance); | |
514 | ||
515 | wrote = 1; | |
516 | } | |
517 | else | |
518 | wrote = 0; | |
519 | ||
520 | if ((temp = cupsGetDest(dest->name, dest->instance, num_temps, temps)) == NULL) | |
521 | temp = cupsGetDest(dest->name, NULL, num_temps, temps); | |
522 | ||
523 | for (j = dest->num_options, option = dest->options; j > 0; j --, option ++) | |
524 | { | |
525 | /* | |
526 | * See if the server/global options match these; if so, don't | |
527 | * write 'em. | |
528 | */ | |
529 | ||
530 | if (temp && (val = cupsGetOption(option->name, temp->num_options, | |
531 | temp->options)) != NULL) | |
532 | { | |
533 | if (strcasecmp(val, option->value) == 0) | |
534 | continue; | |
535 | } | |
536 | ||
537 | /* | |
538 | * Options don't match, write to the file... | |
539 | */ | |
540 | ||
541 | if (!wrote) | |
542 | { | |
543 | fprintf(fp, "Dest %s", dest->name); | |
544 | if (dest->instance) | |
545 | fprintf(fp, "/%s", dest->instance); | |
546 | wrote = 1; | |
547 | } | |
548 | ||
549 | if (option->value[0]) | |
550 | { | |
551 | if (strchr(option->value, ' ') != NULL) | |
552 | fprintf(fp, " %s=\"%s\"", option->name, option->value); | |
553 | else | |
554 | fprintf(fp, " %s=%s", option->name, option->value); | |
555 | } | |
556 | else | |
557 | fprintf(fp, " %s", option->name); | |
558 | } | |
559 | ||
560 | if (wrote) | |
561 | fputs("\n", fp); | |
562 | } | |
563 | ||
564 | /* | |
565 | * Free the temporary destinations... | |
566 | */ | |
567 | ||
568 | cupsFreeDests(num_temps, temps); | |
569 | ||
570 | /* | |
571 | * Close the file and return... | |
572 | */ | |
573 | ||
574 | fclose(fp); | |
575 | ||
576 | return (0); | |
577 | } | |
578 | ||
579 | ||
580 | /* | |
581 | * 'cups_get_dests()' - Get destinations from a file. | |
582 | */ | |
583 | ||
584 | static int /* O - Number of destinations */ | |
585 | cups_get_dests(const char *filename, /* I - File to read from */ | |
586 | int num_dests, /* I - Number of destinations */ | |
587 | cups_dest_t **dests) /* IO - Destinations */ | |
588 | { | |
589 | int i; /* Looping var */ | |
590 | cups_dest_t *dest; /* Current destination */ | |
591 | FILE *fp; /* File pointer */ | |
592 | char line[8192], /* Line from file */ | |
593 | *lineptr, /* Pointer into line */ | |
594 | *name, /* Name of destination/option */ | |
595 | *instance; /* Instance of destination */ | |
596 | const char *printer; /* PRINTER or LPDEST */ | |
597 | ||
598 | ||
599 | /* | |
600 | * Check environment variables... | |
601 | */ | |
602 | ||
603 | if ((printer = getenv("LPDEST")) == NULL) | |
604 | if ((printer = getenv("PRINTER")) != NULL) | |
605 | if (strcmp(printer, "lp") == 0) | |
606 | printer = NULL; | |
607 | ||
608 | /* | |
609 | * Try to open the file... | |
610 | */ | |
611 | ||
612 | if ((fp = fopen(filename, "r")) == NULL) | |
613 | return (num_dests); | |
614 | ||
615 | /* | |
616 | * Read each printer; each line looks like: | |
617 | * | |
618 | * Dest name[/instance] options | |
619 | * Default name[/instance] options | |
620 | */ | |
621 | ||
622 | while (fgets(line, sizeof(line), fp) != NULL) | |
623 | { | |
624 | /* | |
625 | * See what type of line it is... | |
626 | */ | |
627 | ||
628 | if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4] & 255)) | |
629 | lineptr = line + 4; | |
630 | else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255)) | |
631 | lineptr = line + 7; | |
632 | else | |
633 | continue; | |
634 | ||
635 | /* | |
636 | * Skip leading whitespace... | |
637 | */ | |
638 | ||
639 | while (isspace(*lineptr & 255)) | |
640 | lineptr ++; | |
641 | ||
642 | if (!*lineptr) | |
643 | continue; | |
644 | ||
645 | name = lineptr; | |
646 | ||
647 | /* | |
648 | * Search for an instance... | |
649 | */ | |
650 | ||
651 | while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/') | |
652 | lineptr ++; | |
653 | ||
654 | if (!*lineptr) | |
655 | continue; | |
656 | ||
657 | if (*lineptr == '/') | |
658 | { | |
659 | /* | |
660 | * Found an instance... | |
661 | */ | |
662 | ||
663 | *lineptr++ = '\0'; | |
664 | instance = lineptr; | |
665 | ||
666 | /* | |
667 | * Search for an instance... | |
668 | */ | |
669 | ||
670 | while (!isspace(*lineptr & 255) && *lineptr) | |
671 | lineptr ++; | |
672 | } | |
673 | else | |
674 | instance = NULL; | |
675 | ||
676 | *lineptr++ = '\0'; | |
677 | ||
678 | /* | |
679 | * See if the primary instance of the destination exists; if not, | |
680 | * ignore this entry and move on... | |
681 | */ | |
682 | ||
683 | if (cupsGetDest(name, NULL, num_dests, *dests) == NULL) | |
684 | continue; | |
685 | ||
686 | /* | |
687 | * Add the destination... | |
688 | */ | |
689 | ||
690 | num_dests = cupsAddDest(name, instance, num_dests, dests); | |
691 | ||
692 | if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL) | |
693 | { | |
694 | /* | |
695 | * Out of memory! | |
696 | */ | |
697 | ||
698 | fclose(fp); | |
699 | return (num_dests); | |
700 | } | |
701 | ||
702 | /* | |
703 | * Add options until we hit the end of the line... | |
704 | */ | |
705 | ||
706 | dest->num_options = cupsParseOptions(lineptr, dest->num_options, | |
707 | &(dest->options)); | |
708 | ||
709 | /* | |
710 | * Set this as default if needed... | |
711 | */ | |
712 | ||
713 | if (strncasecmp(line, "default", 7) == 0 && printer == NULL) | |
714 | { | |
715 | for (i = 0; i < num_dests; i ++) | |
716 | (*dests)[i].is_default = 0; | |
717 | ||
718 | dest->is_default = 1; | |
719 | } | |
720 | } | |
721 | ||
722 | /* | |
723 | * Close the file and return... | |
724 | */ | |
725 | ||
726 | fclose(fp); | |
727 | ||
728 | return (num_dests); | |
729 | } | |
730 | ||
731 | ||
732 | /* | |
733 | * 'cups_get_sdests()' - Get destinations from a server. | |
734 | */ | |
735 | ||
736 | static int /* O - Number of destinations */ | |
737 | cups_get_sdests(http_t *http, /* I - HTTP connection */ | |
738 | ipp_op_t op, /* I - get-printers or get-classes */ | |
739 | int num_dests, /* I - Number of destinations */ | |
740 | cups_dest_t **dests) /* IO - Destinations */ | |
741 | { | |
742 | cups_dest_t *dest; /* Current destination */ | |
743 | ipp_t *request, /* IPP Request */ | |
744 | *response; /* IPP Response */ | |
745 | ipp_attribute_t *attr; /* Current attribute */ | |
746 | cups_lang_t *language; /* Default language */ | |
747 | const char *name; /* printer-name attribute */ | |
748 | char job_sheets[1024]; /* job-sheets option */ | |
749 | static const char * const pattrs[] = /* Attributes we're interested in */ | |
750 | { | |
751 | "printer-name", | |
752 | "job-sheets-default" | |
753 | }; | |
754 | ||
755 | ||
756 | /* | |
757 | * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require | |
758 | * the following attributes: | |
759 | * | |
760 | * attributes-charset | |
761 | * attributes-natural-language | |
762 | */ | |
763 | ||
764 | request = ippNew(); | |
765 | ||
766 | request->request.op.operation_id = op; | |
767 | request->request.op.request_id = 1; | |
768 | ||
769 | language = cupsLangDefault(); | |
770 | ||
771 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, | |
772 | "attributes-charset", NULL, cupsLangEncoding(language)); | |
773 | ||
774 | ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, | |
775 | "attributes-natural-language", NULL, language->language); | |
776 | ||
777 | cupsLangFree(language); | |
778 | ||
779 | ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, | |
780 | "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), | |
781 | NULL, pattrs); | |
782 | ||
783 | /* | |
784 | * Do the request and get back a response... | |
785 | */ | |
786 | ||
787 | if ((response = cupsDoRequest(http, request, "/")) != NULL) | |
788 | { | |
789 | for (attr = response->attrs; attr != NULL; attr = attr->next) | |
790 | { | |
791 | /* | |
792 | * Skip leading attributes until we hit a printer... | |
793 | */ | |
794 | ||
795 | while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) | |
796 | attr = attr->next; | |
797 | ||
798 | if (attr == NULL) | |
799 | break; | |
800 | ||
801 | /* | |
802 | * Pull the needed attributes from this job... | |
803 | */ | |
804 | ||
805 | name = NULL; | |
806 | ||
807 | strcpy(job_sheets, ""); | |
808 | ||
809 | while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) | |
810 | { | |
811 | if (strcmp(attr->name, "printer-name") == 0 && | |
812 | attr->value_tag == IPP_TAG_NAME) | |
813 | name = attr->values[0].string.text; | |
814 | ||
815 | if (strcmp(attr->name, "job-sheets-default") == 0 && | |
816 | (attr->value_tag == IPP_TAG_KEYWORD || | |
817 | attr->value_tag == IPP_TAG_NAME)) | |
818 | { | |
819 | if (attr->num_values == 2) | |
820 | snprintf(job_sheets, sizeof(job_sheets), "%s,%s", | |
821 | attr->values[0].string.text, attr->values[1].string.text); | |
822 | else | |
823 | strcpy(job_sheets, attr->values[0].string.text); | |
824 | } | |
825 | ||
826 | attr = attr->next; | |
827 | } | |
828 | ||
829 | /* | |
830 | * See if we have everything needed... | |
831 | */ | |
832 | ||
833 | if (!name) | |
834 | { | |
835 | if (attr == NULL) | |
836 | break; | |
837 | else | |
838 | continue; | |
839 | } | |
840 | ||
841 | num_dests = cupsAddDest(name, NULL, num_dests, dests); | |
842 | ||
843 | if ((dest = cupsGetDest(name, NULL, num_dests, *dests)) != NULL) | |
844 | if (job_sheets[0]) | |
845 | dest->num_options = cupsAddOption("job-sheets", job_sheets, 0, | |
846 | &(dest->options)); | |
847 | ||
848 | if (attr == NULL) | |
849 | break; | |
850 | } | |
851 | ||
852 | ippDelete(response); | |
853 | } | |
854 | ||
855 | /* | |
856 | * Return the count... | |
857 | */ | |
858 | ||
859 | return (num_dests); | |
860 | } | |
861 | ||
862 | ||
863 | /* | |
864 | * End of "$Id: dest.c 4918 2006-01-12 05:14:40Z mike $". | |
865 | */ |