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