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