2 * "$Id: dest.c 6943 2007-09-10 23:00:33Z mike $"
4 * User-defined destination (and option) support for the Common UNIX
5 * Printing System (CUPS).
7 * Copyright 2007 by Apple Inc.
8 * Copyright 1997-2007 by Easy Software Products.
10 * These coded instructions, statements, and computer programs are the
11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
16 * This file is subject to the Apple OS-Developed Software exception.
20 * cupsAddDest() - Add a destination to the list of destinations.
21 * cupsFreeDests() - Free the memory used by the list of
23 * cupsGetDest() - Get the named destination from the list.
24 * cupsGetDests() - Get the list of destinations from the default
26 * cupsGetDests2() - Get the list of destinations from the
28 * cupsGetNamedDest() - Get options for the named destination.
29 * cupsRemoveDest() - Remove a destination from the destination list.
30 * cupsDestSetDefaultDest() - Set the default destination.
31 * cupsSetDests() - Set the list of destinations for the default
33 * cupsSetDests2() - Set the list of destinations for the specified
35 * cups_get_dests() - Get destinations from a file.
36 * cups_get_sdests() - Get destinations from a server.
40 * Include necessary headers...
51 #endif /* HAVE_NOTIFY_H */
58 static const char *cups_get_default(const char *filename
, char *namebuf
,
59 size_t namesize
, const char **instance
);
60 static int cups_get_dests(const char *filename
, const char *match_name
,
61 const char *match_inst
, int num_dests
,
63 static int cups_get_sdests(http_t
*http
, ipp_op_t op
, const char *name
,
64 int num_dests
, cups_dest_t
**dests
);
68 * 'cupsAddDest()' - Add a destination to the list of destinations.
70 * This function cannot be used to add a new class or printer queue,
71 * it only adds a new container of saved options for the named
72 * destination or instance.
74 * If the named destination already exists, the destination list is
75 * returned unchanged. Adding a new instance of a destination creates
76 * a copy of that destination's options.
78 * Use the cupsSaveDests() function to save the updated list of
79 * destinations to the user's lpoptions file.
82 int /* O - New number of destinations */
83 cupsAddDest(const char *name
, /* I - Destination name */
84 const char *instance
, /* I - Instance name or NULL for none/primary */
85 int num_dests
, /* I - Number of destinations */
86 cups_dest_t
**dests
) /* IO - Destinations */
88 int i
; /* Looping var */
89 cups_dest_t
*dest
; /* Destination pointer */
90 cups_dest_t
*parent
; /* Parent destination */
91 cups_option_t
*option
; /* Current option */
97 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
101 * Add new destination...
105 dest
= malloc(sizeof(cups_dest_t
));
107 dest
= realloc(*dests
, sizeof(cups_dest_t
) * (num_dests
+ 1));
115 * Find where to insert the destination...
118 for (i
= num_dests
; i
> 0; i
--, dest
++)
119 if (strcasecmp(name
, dest
->name
) < 0)
121 else if (!instance
&& dest
->instance
)
123 else if (!strcasecmp(name
, dest
->name
) &&
124 instance
&& dest
->instance
&&
125 strcasecmp(instance
, dest
->instance
) < 0)
129 memmove(dest
+ 1, dest
, i
* sizeof(cups_dest_t
));
132 * Initialize the destination...
135 dest
->name
= _cupsStrAlloc(name
);
136 dest
->is_default
= 0;
137 dest
->num_options
= 0;
138 dest
->options
= (cups_option_t
*)0;
141 dest
->instance
= NULL
;
145 * Copy options from the primary instance...
148 dest
->instance
= _cupsStrAlloc(instance
);
150 if ((parent
= cupsGetDest(name
, NULL
, num_dests
+ 1, *dests
)) != NULL
)
152 for (i
= parent
->num_options
, option
= parent
->options
;
155 dest
->num_options
= cupsAddOption(option
->name
, option
->value
,
161 return (num_dests
+ 1);
166 * 'cupsFreeDests()' - Free the memory used by the list of destinations.
170 cupsFreeDests(int num_dests
, /* I - Number of destinations */
171 cups_dest_t
*dests
) /* I - Destinations */
173 int i
; /* Looping var */
174 cups_dest_t
*dest
; /* Current destination */
177 if (num_dests
== 0 || dests
== NULL
)
180 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
182 _cupsStrFree(dest
->name
);
183 _cupsStrFree(dest
->instance
);
185 cupsFreeOptions(dest
->num_options
, dest
->options
);
193 * 'cupsGetDest()' - Get the named destination from the list.
195 * Use the cupsGetDests() or cupsGetDests2() functions to get a
196 * list of supported destinations for the current user.
199 cups_dest_t
* /* O - Destination pointer or NULL */
200 cupsGetDest(const char *name
, /* I - Destination name or NULL for the default destination */
201 const char *instance
, /* I - Instance name or NULL */
202 int num_dests
, /* I - Number of destinations */
203 cups_dest_t
*dests
) /* I - Destinations */
205 int comp
; /* Result of comparison */
208 if (num_dests
<= 0 || !dests
)
214 * NULL name for default printer.
217 while (num_dests
> 0)
219 if (dests
->is_default
)
229 * Lookup name and optionally the instance...
232 while (num_dests
> 0)
234 if ((comp
= strcasecmp(name
, dests
->name
)) < 0)
238 if ((!instance
&& !dests
->instance
) ||
239 (instance
!= NULL
&& dests
->instance
!= NULL
&&
240 !strcasecmp(instance
, dests
->instance
)))
254 * 'cupsGetDests()' - Get the list of destinations from the default server.
256 * Starting with CUPS 1.2, the returned list of destinations include the
257 * printer-info, printer-is-accepting-jobs, printer-is-shared,
258 * printer-make-and-model, printer-state, printer-state-change-time,
259 * printer-state-reasons, and printer-type attributes as options.
261 * Use the cupsFreeDests() function to free the destination list and
262 * the cupsGetDest() function to find a particular destination.
265 int /* O - Number of destinations */
266 cupsGetDests(cups_dest_t
**dests
) /* O - Destinations */
268 int num_dests
; /* Number of destinations */
269 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
273 * Connect to the CUPS server and get the destination list and options...
277 cg
->http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
279 num_dests
= cupsGetDests2(cg
->http
, dests
);
286 * 'cupsGetDests2()' - Get the list of destinations from the specified server.
288 * Starting with CUPS 1.2, the returned list of destinations include the
289 * printer-info, printer-is-accepting-jobs, printer-is-shared,
290 * printer-make-and-model, printer-state, printer-state-change-time,
291 * printer-state-reasons, and printer-type attributes as options.
293 * Use the cupsFreeDests() function to free the destination list and
294 * the cupsGetDest() function to find a particular destination.
296 * @since CUPS 1.1.21@
299 int /* O - Number of destinations */
300 cupsGetDests2(http_t
*http
, /* I - HTTP connection */
301 cups_dest_t
**dests
) /* O - Destinations */
303 int i
; /* Looping var */
304 int num_dests
; /* Number of destinations */
305 cups_dest_t
*dest
; /* Destination pointer */
306 const char *home
; /* HOME environment variable */
307 char filename
[1024]; /* Local ~/.cups/lpoptions file */
308 const char *defprinter
; /* Default printer */
309 char name
[1024], /* Copy of printer name */
310 *instance
; /* Pointer to instance name */
311 int num_reals
; /* Number of real queues */
312 cups_dest_t
*reals
; /* Real queues */
313 _cups_globals_t
*cg
= _cupsGlobals(); /* Global data */
317 * Range check the input...
324 * Initialize destination array...
328 *dests
= (cups_dest_t
*)0;
331 * Grab the printers and classes...
334 num_dests
= cups_get_sdests(http
, CUPS_GET_PRINTERS
, NULL
, num_dests
, dests
);
335 num_dests
= cups_get_sdests(http
, CUPS_GET_CLASSES
, NULL
, num_dests
, dests
);
338 * Make a copy of the "real" queues for a later sanity check...
343 num_reals
= num_dests
;
344 reals
= calloc(num_reals
, sizeof(cups_dest_t
));
347 memcpy(reals
, *dests
, num_reals
* sizeof(cups_dest_t
));
358 * Grab the default destination...
361 if ((defprinter
= cupsGetDefault2(http
)) != NULL
)
364 * Grab printer and instance name...
367 strlcpy(name
, defprinter
, sizeof(name
));
369 if ((instance
= strchr(name
, '/')) != NULL
)
373 * Lookup the printer and instance and make it the default...
376 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
377 dest
->is_default
= 1;
382 * This initialization of "instance" is unnecessary, but avoids a
383 * compiler warning...
390 * Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
393 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
394 num_dests
= cups_get_dests(filename
, NULL
, NULL
, num_dests
, dests
);
396 if ((home
= getenv("HOME")) != NULL
)
398 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
399 if (access(filename
, 0))
400 snprintf(filename
, sizeof(filename
), "%s/.lpoptions", home
);
402 num_dests
= cups_get_dests(filename
, NULL
, NULL
, num_dests
, dests
);
406 * Validate the current default destination - this prevents old
407 * Default lines in /etc/cups/lpoptions and ~/.cups/lpoptions from
408 * pointing to a non-existent printer or class...
414 * See if we have a default printer...
417 if ((dest
= cupsGetDest(NULL
, NULL
, num_dests
, *dests
)) != NULL
)
420 * Have a default; see if it is real...
423 dest
= cupsGetDest(dest
->name
, NULL
, num_reals
, reals
);
427 * If dest is NULL, then no default (that exists) is set, so we
428 * need to set a default if one exists...
431 if (dest
== NULL
&& defprinter
!= NULL
)
433 for (i
= 0; i
< num_dests
; i
++)
434 (*dests
)[i
].is_default
= 0;
436 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) != NULL
)
437 dest
->is_default
= 1;
448 * Return the number of destinations...
456 * 'cupsGetNamedDest()' - Get options for the named destination.
458 * This function is optimized for retrieving a single destination and should
459 * be used instead of cupsGetDests() and cupsGetDest() when you either know
460 * the name of the destination or want to print to the default destination.
461 * If NULL is returned, the destination does not exist or there is no default
464 * If "http" is NULL, the connection to the default print server will be used.
466 * If "name" is NULL, the default printer for the current user will be returned.
468 * The returned destination must be freed using cupsFreeDests() with a
474 cups_dest_t
* /* O - Destination or NULL */
475 cupsGetNamedDest(http_t
*http
, /* I - HTTP connection or NULL */
476 const char *name
, /* I - Destination name or NULL */
477 const char *instance
) /* I - Instance name or NULL */
479 cups_dest_t
*dest
; /* Destination */
480 char filename
[1024], /* Path to lpoptions */
481 defname
[256]; /* Default printer name */
482 const char *home
= getenv("HOME"); /* Home directory */
483 ipp_op_t op
= IPP_GET_PRINTER_ATTRIBUTES
;
484 /* IPP operation to get server ops */
485 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
489 * Connect to the server as needed...
495 (cg
->http
= httpConnectEncrypt(cupsServer(), ippPort(),
496 cupsEncryption())) == NULL
)
503 * If "name" is NULL, find the default destination...
508 if ((name
= getenv("LPDEST")) == NULL
)
509 if ((name
= getenv("PRINTER")) != NULL
&& !strcmp(name
, "lp"))
515 * No default in the environment, try the user's lpoptions files...
518 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
520 if ((name
= cups_get_default(filename
, defname
, sizeof(defname
),
523 snprintf(filename
, sizeof(filename
), "%s/.lpoptions", home
);
524 name
= cups_get_default(filename
, defname
, sizeof(defname
),
532 * Still not there? Try the system lpoptions file...
535 snprintf(filename
, sizeof(filename
), "%s/lpoptions",
536 cg
->cups_serverroot
);
537 name
= cups_get_default(filename
, defname
, sizeof(defname
), &instance
);
543 * No locally-set default destination, ask the server...
546 op
= CUPS_GET_DEFAULT
;
551 * Get the printer's attributes...
554 if (!cups_get_sdests(http
, op
, name
, 0, &dest
))
558 dest
->instance
= _cupsStrAlloc(instance
);
561 * Then add local options...
564 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
565 cups_get_dests(filename
, name
, instance
, 1, &dest
);
569 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
571 if (access(filename
, 0))
572 snprintf(filename
, sizeof(filename
), "%s/.lpoptions", home
);
574 cups_get_dests(filename
, name
, instance
, 1, &dest
);
578 * Return the result...
586 * 'cupsRemoveDest()' - Remove a destination from the destination list.
588 * Removing a destination/instance does not delete the class or printer
589 * queue, merely the lpoptions for that destination/instance. Use the
590 * cupsSetDests() or cupsSetDests2() functions to save the new options
596 int /* O - New number of destinations */
597 cupsRemoveDest(const char *name
, /* I - Destination name */
598 const char *instance
, /* I - Instance name or NULL */
599 int num_dests
, /* I - Number of destinations */
600 cups_dest_t
**dests
) /* IO - Destinations */
602 int i
; /* Index into destinations */
603 cups_dest_t
*dest
; /* Pointer to destination */
607 * Find the destination...
610 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) == NULL
)
617 _cupsStrFree(dest
->name
);
618 _cupsStrFree(dest
->instance
);
619 cupsFreeOptions(dest
->num_options
, dest
->options
);
622 * Remove the destination from the array...
630 memmove(dest
, dest
+ 1, (num_dests
- i
) * sizeof(cups_dest_t
));
637 * 'cupsDestSetDefaultDest()' - Set the default destination.
644 const char *name
, /* I - Destination name */
645 const char *instance
, /* I - Instance name or NULL */
646 int num_dests
, /* I - Number of destinations */
647 cups_dest_t
*dests
) /* I - Destinations */
649 int i
; /* Looping var */
650 cups_dest_t
*dest
; /* Current destination */
654 * Range check input...
657 if (!name
|| num_dests
<= 0 || !dests
)
661 * Loop through the array and set the "is_default" flag for the matching
665 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
666 dest
->is_default
= !strcasecmp(name
, dest
->name
) &&
667 ((!instance
&& !dest
->instance
) ||
668 (instance
&& dest
->instance
&&
669 !strcasecmp(instance
, dest
->instance
)));
674 * 'cupsSetDests()' - Save the list of destinations for the default server.
676 * This function saves the destinations to /etc/cups/lpoptions when run
677 * as root and ~/.cups/lpoptions when run as a normal user.
681 cupsSetDests(int num_dests
, /* I - Number of destinations */
682 cups_dest_t
*dests
) /* I - Destinations */
684 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
688 * Connect to the CUPS server and save the destination list and options...
692 cg
->http
= httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
694 cupsSetDests2(cg
->http
, num_dests
, dests
);
699 * 'cupsSetDests2()' - Save the list of destinations for the specified server.
701 * This function saves the destinations to /etc/cups/lpoptions when run
702 * as root and ~/.cups/lpoptions when run as a normal user.
704 * @since CUPS 1.1.21@
707 int /* O - 0 on success, -1 on error */
708 cupsSetDests2(http_t
*http
, /* I - HTTP connection */
709 int num_dests
, /* I - Number of destinations */
710 cups_dest_t
*dests
) /* I - Destinations */
712 int i
, j
; /* Looping vars */
713 int wrote
; /* Wrote definition? */
714 cups_dest_t
*dest
; /* Current destination */
715 cups_option_t
*option
; /* Current option */
716 _ipp_option_t
*match
; /* Matching attribute for option */
717 FILE *fp
; /* File pointer */
719 const char *home
; /* HOME environment variable */
721 char filename
[1024]; /* lpoptions file */
722 int num_temps
; /* Number of temporary destinations */
723 cups_dest_t
*temps
, /* Temporary destinations */
724 *temp
; /* Current temporary dest */
725 const char *val
; /* Value of temporary option */
726 _cups_globals_t
*cg
= _cupsGlobals(); /* Global data */
730 * Range check the input...
733 if (!http
|| !num_dests
|| !dests
)
737 * Get the server destinations...
740 num_temps
= cups_get_sdests(http
, CUPS_GET_PRINTERS
, NULL
, 0, &temps
);
741 num_temps
= cups_get_sdests(http
, CUPS_GET_CLASSES
, NULL
, num_temps
, &temps
);
744 * Figure out which file to write to...
747 snprintf(filename
, sizeof(filename
), "%s/lpoptions", cg
->cups_serverroot
);
753 * Merge in server defaults...
756 num_temps
= cups_get_dests(filename
, NULL
, NULL
, num_temps
, &temps
);
759 * Point to user defaults...
762 if ((home
= getenv("HOME")) != NULL
)
765 * Remove the old ~/.lpoptions file...
768 snprintf(filename
, sizeof(filename
), "%s/.lpoptions", home
);
772 * Create ~/.cups subdirectory...
775 snprintf(filename
, sizeof(filename
), "%s/.cups", home
);
776 if (access(filename
, 0))
777 mkdir(filename
, 0700);
779 snprintf(filename
, sizeof(filename
), "%s/.cups/lpoptions", home
);
785 * Try to open the file...
788 if ((fp
= fopen(filename
, "w")) == NULL
)
790 cupsFreeDests(num_temps
, temps
);
796 * Set the permissions to 0644 when saving to the /etc/cups/lpoptions
801 fchmod(fileno(fp
), 0644);
805 * Write each printer; each line looks like:
807 * Dest name[/instance] options
808 * Default name[/instance] options
811 for (i
= num_dests
, dest
= dests
; i
> 0; i
--, dest
++)
812 if (dest
->instance
!= NULL
|| dest
->num_options
!= 0 || dest
->is_default
)
814 if (dest
->is_default
)
816 fprintf(fp
, "Default %s", dest
->name
);
818 fprintf(fp
, "/%s", dest
->instance
);
825 if ((temp
= cupsGetDest(dest
->name
, dest
->instance
, num_temps
, temps
)) == NULL
)
826 temp
= cupsGetDest(dest
->name
, NULL
, num_temps
, temps
);
828 for (j
= dest
->num_options
, option
= dest
->options
; j
> 0; j
--, option
++)
831 * See if this option is a printer attribute; if so, skip it...
834 if ((match
= _ippFindOption(option
->name
)) != NULL
&&
835 match
->group_tag
== IPP_TAG_PRINTER
)
839 * See if the server/global options match these; if so, don't
844 (val
= cupsGetOption(option
->name
, temp
->num_options
,
845 temp
->options
)) != NULL
&&
846 !strcasecmp(val
, option
->value
))
850 * Options don't match, write to the file...
855 fprintf(fp
, "Dest %s", dest
->name
);
857 fprintf(fp
, "/%s", dest
->instance
);
861 if (option
->value
[0])
863 if (strchr(option
->value
, ' ') ||
864 strchr(option
->value
, '\\') ||
865 strchr(option
->value
, '\"') ||
866 strchr(option
->value
, '\''))
872 fprintf(fp
, " %s=\"", option
->name
);
874 for (val
= option
->value
; *val
; val
++)
876 if (strchr("\"\'\\", *val
))
887 * Store the literal value...
890 fprintf(fp
, " %s=%s", option
->name
, option
->value
);
894 fprintf(fp
, " %s", option
->name
);
902 * Free the temporary destinations and close the file...
905 cupsFreeDests(num_temps
, temps
);
909 #ifdef HAVE_NOTIFY_POST
911 * Send a notification so that MacOS X applications can know about the
915 notify_post("com.apple.printerListChange");
916 #endif /* HAVE_NOTIFY_POST */
923 * 'cups_get_default()' - Get the default destination from an lpoptions file.
926 static const char * /* O - Default destination or NULL */
927 cups_get_default(const char *filename
, /* I - File to read */
928 char *namebuf
, /* I - Name buffer */
929 size_t namesize
, /* I - Size of name buffer */
930 const char **instance
) /* I - Instance */
932 cups_file_t
*fp
; /* lpoptions file */
933 char line
[8192], /* Line from file */
934 *value
, /* Value for line */
935 *nameptr
; /* Pointer into name */
936 int linenum
; /* Current line */
941 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
945 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
947 if (!strcasecmp(line
, "default") && value
)
949 strlcpy(namebuf
, value
, namesize
);
951 if ((nameptr
= strchr(namebuf
, ' ')) != NULL
)
953 if ((nameptr
= strchr(namebuf
, '\t')) != NULL
)
956 if ((nameptr
= strchr(namebuf
, '/')) != NULL
)
967 return (*namebuf
? namebuf
: NULL
);
972 * 'cups_get_dests()' - Get destinations from a file.
975 static int /* O - Number of destinations */
976 cups_get_dests(const char *filename
, /* I - File to read from */
977 const char *match_name
, /* I - Destination name we want */
978 const char *match_inst
, /* I - Instance name we want */
979 int num_dests
, /* I - Number of destinations */
980 cups_dest_t
**dests
) /* IO - Destinations */
982 int i
; /* Looping var */
983 cups_dest_t
*dest
; /* Current destination */
984 cups_file_t
*fp
; /* File pointer */
985 char line
[8192], /* Line from file */
986 *lineptr
, /* Pointer into line */
987 *name
, /* Name of destination/option */
988 *instance
; /* Instance of destination */
989 int linenum
; /* Current line number */
990 const char *printer
; /* PRINTER or LPDEST */
993 DEBUG_printf(("cups_get_dests(filename=\"%s\", match_name=\"%s\", "
994 "match_inst=\"%s\", num_dests=%d, dests=%p)\n", filename
,
995 match_name
? match_name
: "(null)",
996 match_inst
? match_inst
: "(null)", num_dests
, dests
));
999 * Try to open the file...
1002 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1006 * Check environment variables...
1009 if ((printer
= getenv("LPDEST")) == NULL
)
1010 if ((printer
= getenv("PRINTER")) != NULL
)
1011 if (strcmp(printer
, "lp") == 0)
1014 DEBUG_printf(("cups_get_dests: printer=\"%s\"\n",
1015 printer
? printer
: "(null)"));
1018 * Read each printer; each line looks like:
1020 * Dest name[/instance] options
1021 * Default name[/instance] options
1026 while (cupsFileGetConf(fp
, line
, sizeof(line
), &lineptr
, &linenum
))
1029 * See what type of line it is...
1032 DEBUG_printf(("cups_get_dests: linenum=%d line=\"%s\" lineptr=\"%s\"\n",
1033 linenum
, line
, lineptr
? lineptr
: "(null)"));
1035 if ((strcasecmp(line
, "dest") && strcasecmp(line
, "default")) || !lineptr
)
1037 DEBUG_puts("cups_get_dests: Not a dest or default line...");
1044 * Search for an instance...
1047 while (!isspace(*lineptr
& 255) && *lineptr
&& *lineptr
!= '/')
1050 if (*lineptr
== '/')
1053 * Found an instance...
1060 * Search for an instance...
1063 while (!isspace(*lineptr
& 255) && *lineptr
)
1072 DEBUG_printf(("cups_get_dests: name=\"%s\", instance=\"%s\"\n", name
,
1076 * See if the primary instance of the destination exists; if not,
1077 * ignore this entry and move on...
1082 if (strcasecmp(name
, match_name
) ||
1083 (!instance
&& match_inst
) ||
1084 (instance
&& !match_inst
) ||
1085 (instance
&& strcasecmp(instance
, match_inst
)))
1090 else if (cupsGetDest(name
, NULL
, num_dests
, *dests
) == NULL
)
1092 DEBUG_puts("cups_get_dests: Not found!");
1098 * Add the destination...
1101 num_dests
= cupsAddDest(name
, instance
, num_dests
, dests
);
1103 if ((dest
= cupsGetDest(name
, instance
, num_dests
, *dests
)) == NULL
)
1109 DEBUG_puts("cups_get_dests: Out of memory!");
1115 * Add options until we hit the end of the line...
1118 dest
->num_options
= cupsParseOptions(lineptr
, dest
->num_options
,
1122 * If we found what we were looking for, stop now...
1129 * Set this as default if needed...
1132 if (!printer
&& !strcasecmp(line
, "default"))
1134 DEBUG_puts("cups_get_dests: Setting as default...");
1136 for (i
= 0; i
< num_dests
; i
++)
1137 (*dests
)[i
].is_default
= 0;
1139 dest
->is_default
= 1;
1144 * Close the file and return...
1154 * 'cups_get_sdests()' - Get destinations from a server.
1157 static int /* O - Number of destinations */
1158 cups_get_sdests(http_t
*http
, /* I - HTTP connection */
1159 ipp_op_t op
, /* I - IPP operation */
1160 const char *name
, /* I - Name of destination */
1161 int num_dests
, /* I - Number of destinations */
1162 cups_dest_t
**dests
) /* IO - Destinations */
1164 int i
; /* Looping var */
1165 cups_dest_t
*dest
; /* Current destination */
1166 ipp_t
*request
, /* IPP Request */
1167 *response
; /* IPP Response */
1168 ipp_attribute_t
*attr
; /* Current attribute */
1169 int accepting
, /* printer-is-accepting-jobs attribute */
1170 shared
, /* printer-is-shared attribute */
1171 state
, /* printer-state attribute */
1172 change_time
, /* printer-state-change-time attribute */
1173 type
; /* printer-type attribute */
1174 const char *info
, /* printer-info attribute */
1175 *location
, /* printer-location attribute */
1176 *make_model
, /* printer-make-and-model attribute */
1177 *printer_name
; /* printer-name attribute */
1178 char uri
[1024], /* printer-uri value */
1179 job_sheets
[1024], /* job-sheets-default attribute */
1180 auth_info_req
[1024], /* auth-info-required attribute */
1181 reasons
[1024]; /* printer-state-reasons attribute */
1182 int num_options
; /* Number of options */
1183 cups_option_t
*options
; /* Options */
1184 char optname
[1024], /* Option name */
1185 value
[2048], /* Option value */
1186 *ptr
; /* Pointer into name/value */
1187 static const char * const pattrs
[] = /* Attributes we're interested in */
1189 "auth-info-required",
1190 "job-sheets-default",
1192 "printer-is-accepting-jobs",
1193 "printer-is-shared",
1195 "printer-make-and-model",
1198 "printer-state-change-time",
1199 "printer-state-reasons",
1206 * Build a CUPS_GET_PRINTERS or CUPS_GET_CLASSES request, which require
1207 * the following attributes:
1209 * attributes-charset
1210 * attributes-natural-language
1211 * requesting-user-name
1214 request
= ippNewRequest(op
);
1216 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1217 "requested-attributes", sizeof(pattrs
) / sizeof(pattrs
[0]),
1220 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1221 "requesting-user-name", NULL
, cupsUser());
1225 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1226 "localhost", ippPort(), "/printers/%s", name
);
1227 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
1232 * Do the request and get back a response...
1235 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1237 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1240 * Skip leading attributes until we hit a printer...
1243 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
1250 * Pull the needed attributes from this printer...
1258 printer_name
= NULL
;
1262 state
= IPP_PRINTER_IDLE
;
1263 type
= CUPS_PRINTER_LOCAL
;
1265 auth_info_req
[0] = '\0';
1266 job_sheets
[0] = '\0';
1269 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
)
1271 if (!strcmp(attr
->name
, "auth-info-required") &&
1272 attr
->value_tag
== IPP_TAG_KEYWORD
)
1274 strlcpy(auth_info_req
, attr
->values
[0].string
.text
,
1275 sizeof(auth_info_req
));
1277 for (i
= 1, ptr
= auth_info_req
+ strlen(auth_info_req
);
1278 i
< attr
->num_values
;
1281 snprintf(ptr
, sizeof(auth_info_req
) - (ptr
- auth_info_req
), ",%s",
1282 attr
->values
[i
].string
.text
);
1286 else if (!strcmp(attr
->name
, "job-sheets-default") &&
1287 (attr
->value_tag
== IPP_TAG_KEYWORD
||
1288 attr
->value_tag
== IPP_TAG_NAME
))
1290 if (attr
->num_values
== 2)
1291 snprintf(job_sheets
, sizeof(job_sheets
), "%s,%s",
1292 attr
->values
[0].string
.text
, attr
->values
[1].string
.text
);
1294 strlcpy(job_sheets
, attr
->values
[0].string
.text
,
1295 sizeof(job_sheets
));
1297 else if (!strcmp(attr
->name
, "printer-info") &&
1298 attr
->value_tag
== IPP_TAG_TEXT
)
1299 info
= attr
->values
[0].string
.text
;
1300 else if (!strcmp(attr
->name
, "printer-is-accepting-jobs") &&
1301 attr
->value_tag
== IPP_TAG_BOOLEAN
)
1302 accepting
= attr
->values
[0].boolean
;
1303 else if (!strcmp(attr
->name
, "printer-is-shared") &&
1304 attr
->value_tag
== IPP_TAG_BOOLEAN
)
1305 shared
= attr
->values
[0].boolean
;
1306 else if (!strcmp(attr
->name
, "printer-location") &&
1307 attr
->value_tag
== IPP_TAG_TEXT
)
1308 location
= attr
->values
[0].string
.text
;
1309 else if (!strcmp(attr
->name
, "printer-make-and-model") &&
1310 attr
->value_tag
== IPP_TAG_TEXT
)
1311 make_model
= attr
->values
[0].string
.text
;
1312 else if (!strcmp(attr
->name
, "printer-name") &&
1313 attr
->value_tag
== IPP_TAG_NAME
)
1314 printer_name
= attr
->values
[0].string
.text
;
1315 else if (!strcmp(attr
->name
, "printer-state") &&
1316 attr
->value_tag
== IPP_TAG_ENUM
)
1317 state
= attr
->values
[0].integer
;
1318 else if (!strcmp(attr
->name
, "printer-state-change-time") &&
1319 attr
->value_tag
== IPP_TAG_INTEGER
)
1320 change_time
= attr
->values
[0].integer
;
1321 else if (!strcmp(attr
->name
, "printer-state-reasons") &&
1322 attr
->value_tag
== IPP_TAG_KEYWORD
)
1324 strlcpy(reasons
, attr
->values
[0].string
.text
, sizeof(reasons
));
1325 for (i
= 1, ptr
= reasons
+ strlen(reasons
);
1326 i
< attr
->num_values
;
1329 snprintf(ptr
, sizeof(reasons
) - (ptr
- reasons
), ",%s",
1330 attr
->values
[i
].string
.text
);
1334 else if (!strcmp(attr
->name
, "printer-type") &&
1335 attr
->value_tag
== IPP_TAG_ENUM
)
1336 type
= attr
->values
[0].integer
;
1337 else if (strncmp(attr
->name
, "notify-", 7) &&
1338 (attr
->value_tag
== IPP_TAG_BOOLEAN
||
1339 attr
->value_tag
== IPP_TAG_ENUM
||
1340 attr
->value_tag
== IPP_TAG_INTEGER
||
1341 attr
->value_tag
== IPP_TAG_KEYWORD
||
1342 attr
->value_tag
== IPP_TAG_NAME
||
1343 attr
->value_tag
== IPP_TAG_RANGE
) &&
1344 strstr(attr
->name
, "-default"))
1346 char *valptr
; /* Pointer into attribute value */
1350 * Add a default option...
1353 strlcpy(optname
, attr
->name
, sizeof(optname
));
1354 if ((ptr
= strstr(optname
, "-default")) != NULL
)
1358 for (i
= 0, ptr
= value
; i
< attr
->num_values
; i
++)
1360 if (ptr
>= (value
+ sizeof(value
) - 1))
1366 switch (attr
->value_tag
)
1368 case IPP_TAG_INTEGER
:
1370 snprintf(ptr
, sizeof(value
) - (ptr
- value
), "%d",
1371 attr
->values
[i
].integer
);
1374 case IPP_TAG_BOOLEAN
:
1375 if (attr
->values
[i
].boolean
)
1376 strlcpy(ptr
, "true", sizeof(value
) - (ptr
- value
));
1378 strlcpy(ptr
, "false", sizeof(value
) - (ptr
- value
));
1381 case IPP_TAG_RANGE
:
1382 if (attr
->values
[i
].range
.lower
==
1383 attr
->values
[i
].range
.upper
)
1384 snprintf(ptr
, sizeof(value
) - (ptr
- value
), "%d",
1385 attr
->values
[i
].range
.lower
);
1387 snprintf(ptr
, sizeof(value
) - (ptr
- value
), "%d-%d",
1388 attr
->values
[i
].range
.lower
,
1389 attr
->values
[i
].range
.upper
);
1393 for (valptr
= attr
->values
[i
].string
.text
;
1394 *valptr
&& ptr
< (value
+ sizeof(value
) - 2);)
1396 if (strchr(" \t\n\\\'\"", *valptr
))
1409 num_options
= cupsAddOption(optname
, value
, num_options
, &options
);
1416 * See if we have everything needed...
1421 cupsFreeOptions(num_options
, options
);
1429 num_dests
= cupsAddDest(printer_name
, NULL
, num_dests
, dests
);
1431 if ((dest
= cupsGetDest(printer_name
, NULL
, num_dests
, *dests
)) != NULL
)
1433 dest
->num_options
= num_options
;
1434 dest
->options
= options
;
1439 if (auth_info_req
[0])
1440 dest
->num_options
= cupsAddOption("auth-info-required", auth_info_req
,
1445 dest
->num_options
= cupsAddOption("job-sheets", job_sheets
,
1450 dest
->num_options
= cupsAddOption("printer-info", info
,
1454 sprintf(value
, "%d", accepting
);
1455 dest
->num_options
= cupsAddOption("printer-is-accepting-jobs", value
,
1459 sprintf(value
, "%d", shared
);
1460 dest
->num_options
= cupsAddOption("printer-is-shared", value
,
1465 dest
->num_options
= cupsAddOption("printer-location",
1466 location
, dest
->num_options
,
1470 dest
->num_options
= cupsAddOption("printer-make-and-model",
1471 make_model
, dest
->num_options
,
1474 sprintf(value
, "%d", state
);
1475 dest
->num_options
= cupsAddOption("printer-state", value
,
1481 sprintf(value
, "%d", change_time
);
1482 dest
->num_options
= cupsAddOption("printer-state-change-time", value
,
1488 dest
->num_options
= cupsAddOption("printer-state-reasons", reasons
,
1492 sprintf(value
, "%d", type
);
1493 dest
->num_options
= cupsAddOption("printer-type", value
,
1498 cupsFreeOptions(num_options
, options
);
1504 ippDelete(response
);
1508 * Return the count...
1516 * End of "$Id: dest.c 6943 2007-09-10 23:00:33Z mike $".