]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/dest.c
0d8ffd95db5305ae631cdaa70c38d8185e2abd57
2 * "$Id: dest.c 5138 2006-02-21 10:49:06Z mike $"
4 * User-defined destination (and option) support for the Common UNIX
5 * Printing System (CUPS).
7 * Copyright 1997-2006 by Easy Software Products.
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
16 * Attn: CUPS Licensing Information
17 * Easy Software Products
18 * 44141 Airport View Drive, Suite 204
19 * Hollywood, Maryland 20636 USA
21 * Voice: (301) 373-9600
22 * EMail: cups-info@cups.org
23 * WWW: http://www.cups.org
25 * This file is subject to the Apple OS-Developed Software exception.
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.
41 * Include necessary headers...
50 #endif /* HAVE_NOTIFY_H */
57 static int cups_get_dests(const char *filename
, int num_dests
,
59 static int cups_get_sdests(http_t
*http
, ipp_op_t op
, int num_dests
,
64 * 'cupsAddDest()' - Add a destination to the list of destinations.
66 * Use the cupsSaveDests() function to save the updated list of destinations
67 * to the user's lpoptions file.
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 */
76 int i
; /* Looping var */
77 cups_dest_t
*dest
; /* Destination pointer */
80 if (name
== NULL
|| dests
== NULL
)
83 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
87 * Add new destination...
91 dest
= malloc(sizeof(cups_dest_t
));
93 dest
= realloc(*dests
, sizeof(cups_dest_t
) * (num_dests
+ 1));
100 for (i
= num_dests
; i
> 0; i
--, dest
++)
101 if (strcasecmp(name
, dest
->name
) < 0)
103 else if (strcasecmp(name
, dest
->name
) == 0 &&
104 instance
!= NULL
&& dest
->instance
!= NULL
&&
105 strcasecmp(instance
, dest
->instance
) < 0)
109 memmove(dest
+ 1, dest
, i
* sizeof(cups_dest_t
));
111 dest
->name
= strdup(name
);
112 dest
->is_default
= 0;
113 dest
->num_options
= 0;
114 dest
->options
= (cups_option_t
*)0;
116 if (instance
== NULL
)
117 dest
->instance
= NULL
;
119 dest
->instance
= strdup(instance
);
121 return (num_dests
+ 1);
126 * 'cupsFreeDests()' - Free the memory used by the list of destinations.
130 cupsFreeDests(int num_dests
, /* I - Number of destinations */
131 cups_dest_t
*dests
) /* I - Destinations */
133 int i
; /* Looping var */
134 cups_dest_t
*dest
; /* Current destination */
137 if (num_dests
== 0 || dests
== NULL
)
140 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
145 free(dest
->instance
);
147 cupsFreeOptions(dest
->num_options
, dest
->options
);
155 * 'cupsGetDest()' - Get the named destination from the list.
157 * Use the cupsGetDests() or cupsGetDests2() functions to get a
158 * list of supported destinations for the current user.
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 */
167 int comp
; /* Result of comparison */
170 if (num_dests
== 0 || dests
== NULL
)
176 * NULL name for default printer.
179 while (num_dests
> 0)
181 if (dests
->is_default
)
191 * Lookup name and optionally the instance...
194 while (num_dests
> 0)
196 if ((comp
= strcasecmp(name
, dests
->name
)) < 0)
200 if ((instance
== NULL
&& dests
->instance
== NULL
) ||
201 (instance
!= NULL
&& dests
->instance
!= NULL
&&
202 strcasecmp(instance
, dests
->instance
) == 0))
216 * 'cupsGetDests()' - Get the list of destinations from the default server.
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.
224 int /* O - Number of destinations */
225 cupsGetDests(cups_dest_t
**dests
) /* O - Destinations */
227 int num_dests
; /* Number of destinations */
228 http_t
*http
; /* HTTP connection */
232 * Connect to the CUPS server and get the destination list and options...
235 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
237 num_dests
= cupsGetDests2(http
, dests
);
247 * 'cupsGetDests2()' - Get the list of destinations from the specified server.
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.
254 * @since CUPS 1.1.21@
257 int /* O - Number of destinations */
258 cupsGetDests2(http_t
*http
, /* I - HTTP connection */
259 cups_dest_t
**dests
) /* O - Destinations */
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 */
275 * Range check the input...
282 * Initialize destination array...
286 *dests
= (cups_dest_t
*)0;
289 * Grab the printers and classes...
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
);
296 * Make a copy of the "real" queues for a later sanity check...
301 num_reals
= num_dests
;
302 reals
= calloc(num_reals
, sizeof(cups_dest_t
));
305 memcpy(reals
, *dests
, num_reals
* sizeof(cups_dest_t
));
316 * Grab the default destination...
319 if ((defprinter
= cupsGetDefault2(http
)) != NULL
)
322 * Grab printer and instance name...
325 strlcpy(name
, defprinter
, sizeof(name
));
327 if ((instance
= strchr(name
, '/')) != NULL
)
331 * Lookup the printer and instance and make it the default...
334 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
335 dest
->is_default
= 1;
340 * This initialization of "instance" is unnecessary, but avoids a
341 * compiler warning...
348 * Load the /etc/cups/lpoptions and ~/.lpoptions files...
351 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
352 num_dests
= cups_get_dests(filename
, num_dests
, dests
);
354 if ((home
= getenv("HOME")) != NULL
)
356 snprintf(filename
, sizeof(filename
), "%s/.lpoptions", home
);
357 num_dests
= cups_get_dests(filename
, num_dests
, dests
);
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...
369 * See if we have a default printer...
372 if ((dest
= cupsGetDest(NULL
, NULL
, num_dests
, *dests
)) != NULL
)
375 * Have a default; see if it is real...
378 dest
= cupsGetDest(dest
->name
, NULL
, num_reals
, reals
);
382 * If dest is NULL, then no default (that exists) is set, so we
383 * need to set a default if one exists...
386 if (dest
== NULL
&& defprinter
!= NULL
)
388 for (i
= 0; i
< num_dests
; i
++)
389 (*dests
)[i
].is_default
= 0;
391 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
392 dest
->is_default
= 1;
403 * Return the number of destinations...
411 * 'cupsSetDests()' - Save the list of destinations for the default server.
413 * This function saves the destinations to /etc/cups/lpoptions when run
414 * as root and ~/.lpoptions when run as a normal user.
418 cupsSetDests(int num_dests
, /* I - Number of destinations */
419 cups_dest_t
*dests
) /* I - Destinations */
421 http_t
*http
; /* HTTP connection */
425 * Connect to the CUPS server and save the destination list and options...
428 http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
430 cupsSetDests2(http
, num_dests
, dests
);
438 * 'cupsSetDests2()' - Save the list of destinations for the specified server.
440 * This function saves the destinations to /etc/cups/lpoptions when run
441 * as root and ~/.lpoptions when run as a normal user.
443 * @since CUPS 1.1.21@
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 */
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 */
466 * Range check the input...
469 if (!http
|| !num_dests
|| !dests
)
473 * Get the server destinations...
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
);
480 * Figure out which file to write to...
483 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
489 * Merge in server defaults...
492 num_temps
= cups_get_dests(filename
, num_temps
, &temps
);
495 * Point to user defaults...
498 if ((home
= getenv("HOME")) != NULL
)
499 snprintf(filename
, sizeof(filename
), "%s/.lpoptions", home
);
504 * Try to open the file...
507 if ((fp
= fopen(filename
, "w")) == NULL
)
509 cupsFreeDests(num_temps
, temps
);
514 * Write each printer; each line looks like:
516 * Dest name[/instance] options
517 * Default name[/instance] options
520 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
521 if (dest
->instance
!= NULL
|| dest
->num_options
!= 0 || dest
->is_default
)
523 if (dest
->is_default
)
525 fprintf(fp
, "Default %s", dest
->name
);
527 fprintf(fp
, "/%s", dest
->instance
);
534 if ((temp
= cupsGetDest(dest
->name
, dest
->instance
, num_temps
, temps
)) == NULL
)
535 temp
= cupsGetDest(dest
->name
, NULL
, num_temps
, temps
);
537 for (j
= dest
->num_options
, option
= dest
->options
; j
> 0; j
--, option
++)
540 * See if the server/global options match these; if so, don't
544 if (temp
&& (val
= cupsGetOption(option
->name
, temp
->num_options
,
545 temp
->options
)) != NULL
)
547 if (strcasecmp(val
, option
->value
) == 0)
552 * Options don't match, write to the file...
557 fprintf(fp
, "Dest %s", dest
->name
);
559 fprintf(fp
, "/%s", dest
->instance
);
563 if (option
->value
[0])
565 if (strchr(option
->value
, ' ') != NULL
)
566 fprintf(fp
, " %s=\"%s\"", option
->name
, option
->value
);
568 fprintf(fp
, " %s=%s", option
->name
, option
->value
);
571 fprintf(fp
, " %s", option
->name
);
579 * Free the temporary destinations and close the file...
582 cupsFreeDests(num_temps
, temps
);
586 #ifdef HAVE_NOTIFY_POST
588 * Send a notification so that MacOS X applications can know about the
592 notify_post("com.apple.printerListChange");
593 #endif /* HAVE_NOTIFY_POST */
600 * 'cups_get_dests()' - Get destinations from a file.
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 */
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 */
619 * Check environment variables...
622 if ((printer
= getenv("LPDEST")) == NULL
)
623 if ((printer
= getenv("PRINTER")) != NULL
)
624 if (strcmp(printer
, "lp") == 0)
628 * Try to open the file...
631 if ((fp
= fopen(filename
, "r")) == NULL
)
635 * Read each printer; each line looks like:
637 * Dest name[/instance] options
638 * Default name[/instance] options
641 while (fgets(line
, sizeof(line
), fp
) != NULL
)
644 * See what type of line it is...
647 if (strncasecmp(line
, "dest", 4) == 0 && isspace(line
[4] & 255))
649 else if (strncasecmp(line
, "default", 7) == 0 && isspace(line
[7] & 255))
655 * Skip leading whitespace...
658 while (isspace(*lineptr
& 255))
667 * Search for an instance...
670 while (!isspace(*lineptr
& 255) && *lineptr
&& *lineptr
!= '/')
679 * Found an instance...
686 * Search for an instance...
689 while (!isspace(*lineptr
& 255) && *lineptr
)
698 * See if the primary instance of the destination exists; if not,
699 * ignore this entry and move on...
702 if (cupsGetDest(name
, NULL
, num_dests
, *dests
) == NULL
)
706 * Add the destination...
709 num_dests
= cupsAddDest(name
, instance
, num_dests
, dests
);
711 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) == NULL
)
722 * Add options until we hit the end of the line...
725 dest
->num_options
= cupsParseOptions(lineptr
, dest
->num_options
,
729 * Set this as default if needed...
732 if (strncasecmp(line
, "default", 7) == 0 && printer
== NULL
)
734 for (i
= 0; i
< num_dests
; i
++)
735 (*dests
)[i
].is_default
= 0;
737 dest
->is_default
= 1;
742 * Close the file and return...
752 * 'cups_get_sdests()' - Get destinations from a server.
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 */
761 int i
; /* Looping var */
762 cups_dest_t
*dest
; /* Current destination */
763 ipp_t
*request
, /* IPP Request */
764 *response
; /* IPP Response */
765 ipp_attribute_t
*attr
; /* Current attribute */
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 */
778 static const char * const pattrs
[] = /* Attributes we're interested in */
780 "job-sheets-default",
782 "printer-is-accepting-jobs",
784 "printer-make-and-model",
787 "printer-state-change-time",
788 "printer-state-reasons",
794 * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
795 * the following attributes:
798 * attributes-natural-language
799 * requesting-user-name
802 request
= ippNewRequest(op
);
804 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
805 "requested-attributes", sizeof(pattrs
) / sizeof(pattrs
[0]),
808 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
809 "requesting-user-name", NULL
, cupsUser());
812 * Do the request and get back a response...
815 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
817 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
820 * Skip leading attributes until we hit a printer...
823 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
830 * Pull the needed attributes from this job...
839 state
= IPP_PRINTER_IDLE
;
840 type
= CUPS_PRINTER_LOCAL
;
842 strcpy(job_sheets
, "");
845 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
847 if (!strcmp(attr
->name
, "job-sheets-default") &&
848 (attr
->value_tag
== IPP_TAG_KEYWORD
||
849 attr
->value_tag
== IPP_TAG_NAME
))
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
);
855 strlcpy(job_sheets
, attr
->values
[0].string
.text
,
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
)
882 strlcpy(reasons
, attr
->values
[0].string
.text
, sizeof(reasons
));
883 for (i
= 1, rptr
= reasons
+ strlen(reasons
);
884 i
< attr
->num_values
;
887 snprintf(rptr
, sizeof(reasons
) - (rptr
- reasons
), ",%s",
888 attr
->values
[i
].string
.text
);
889 rptr
+= strlen(rptr
);
892 else if (!strcmp(attr
->name
, "printer-type") &&
893 attr
->value_tag
== IPP_TAG_ENUM
)
894 type
= attr
->values
[0].integer
;
900 * See if we have everything needed...
911 num_dests
= cupsAddDest(name
, NULL
, num_dests
, dests
);
913 if ((dest
= cupsGetDest(name
, NULL
, num_dests
, *dests
)) != NULL
)
916 dest
->num_options
= cupsAddOption("job-sheets", job_sheets
,
921 dest
->num_options
= cupsAddOption("printer-info", info
,
925 sprintf(temp
, "%d", accepting
);
926 dest
->num_options
= cupsAddOption("printer-is-accepting-jobs", temp
,
930 sprintf(temp
, "%d", shared
);
931 dest
->num_options
= cupsAddOption("printer-is-shared", temp
,
936 dest
->num_options
= cupsAddOption("printer-make-and-model",
937 make_model
, dest
->num_options
,
940 sprintf(temp
, "%d", state
);
941 dest
->num_options
= cupsAddOption("printer-state", temp
,
947 sprintf(temp
, "%d", change_time
);
948 dest
->num_options
= cupsAddOption("printer-state-change-time", temp
,
954 dest
->num_options
= cupsAddOption("printer-state-reasons", reasons
,
958 sprintf(temp
, "%d", type
);
959 dest
->num_options
= cupsAddOption("printer-type", temp
,
972 * Return the count...
980 * End of "$Id: dest.c 5138 2006-02-21 10:49:06Z mike $".