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