4 * Printing utilities for CUPS.
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * Include necessary headers...
22 #include "cups-private.h"
25 #if defined(WIN32) || defined(__EMX__)
29 #endif /* WIN32 || __EMX__ */
36 static int cups_get_printer_uri(http_t
*http
, const char *name
,
37 char *host
, int hostsize
, int *port
,
38 char *resource
, int resourcesize
,
43 * 'cupsCancelJob()' - Cancel a print job on the default server.
45 * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@
46 * to cancel the current job on the named destination.
48 * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
49 * the cause of any failure.
52 int /* O - 1 on success, 0 on failure */
53 cupsCancelJob(const char *name
, /* I - Name of printer or class */
54 int job_id
) /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */
56 return (cupsCancelJob2(CUPS_HTTP_DEFAULT
, name
, job_id
, 0)
57 < IPP_STATUS_REDIRECTION_OTHER_SITE
);
62 * 'cupsCancelJob2()' - Cancel or purge a print job.
64 * Canceled jobs remain in the job history while purged jobs are removed
65 * from the job history.
67 * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@
68 * to cancel the current job on the named destination.
70 * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
71 * the cause of any failure.
73 * @since CUPS 1.4/OS X 10.6@
76 ipp_status_t
/* O - IPP status */
77 cupsCancelJob2(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
78 const char *name
, /* I - Name of printer or class */
79 int job_id
, /* I - Job ID, @code CUPS_JOBID_CURRENT@ for the current job, or @code CUPS_JOBID_ALL@ for all jobs */
80 int purge
) /* I - 1 to purge, 0 to cancel */
82 char uri
[HTTP_MAX_URI
]; /* Job/printer URI */
83 ipp_t
*request
; /* IPP request */
87 * Range check input...
90 if (job_id
< -1 || (!name
&& job_id
== 0))
92 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
97 * Connect to the default server as needed...
101 if ((http
= _cupsConnect()) == NULL
)
102 return (IPP_STATUS_ERROR_SERVICE_UNAVAILABLE
);
105 * Build an IPP_CANCEL_JOB or IPP_PURGE_JOBS request, which requires the following
109 * attributes-natural-language
110 * job-uri or printer-uri + job-id
111 * requesting-user-name
112 * [purge-job] or [purge-jobs]
115 request
= ippNewRequest(job_id
< 0 ? IPP_OP_PURGE_JOBS
: IPP_OP_CANCEL_JOB
);
119 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
120 "localhost", ippPort(), "/printers/%s", name
);
122 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
,
124 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id",
129 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", job_id
);
131 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
134 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
137 if (purge
&& job_id
>= 0)
138 ippAddBoolean(request
, IPP_TAG_OPERATION
, "purge-job", 1);
139 else if (!purge
&& job_id
< 0)
140 ippAddBoolean(request
, IPP_TAG_OPERATION
, "purge-jobs", 0);
146 ippDelete(cupsDoRequest(http
, request
, "/jobs/"));
148 return (cupsLastError());
153 * 'cupsCreateJob()' - Create an empty job for streaming.
155 * Use this function when you want to stream print data using the
156 * @link cupsStartDocument@, @link cupsWriteRequestData@, and
157 * @link cupsFinishDocument@ functions. If you have one or more files to
158 * print, use the @link cupsPrintFile2@ or @link cupsPrintFiles2@ function
161 * @since CUPS 1.4/OS X 10.6@
164 int /* O - Job ID or 0 on error */
166 http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
167 const char *name
, /* I - Destination name */
168 const char *title
, /* I - Title of job */
169 int num_options
, /* I - Number of options */
170 cups_option_t
*options
) /* I - Options */
172 char printer_uri
[1024], /* Printer URI */
173 resource
[1024]; /* Printer resource */
174 ipp_t
*request
, /* Create-Job request */
175 *response
; /* Create-Job response */
176 ipp_attribute_t
*attr
; /* job-id attribute */
177 int job_id
= 0; /* job-id value */
180 DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", "
181 "num_options=%d, options=%p)",
182 http
, name
, title
, num_options
, options
));
185 * Range check input...
190 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
195 * Build a Create-Job request...
198 if ((request
= ippNewRequest(IPP_OP_CREATE_JOB
)) == NULL
)
200 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(ENOMEM
), 0);
204 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
, sizeof(printer_uri
), "ipp",
205 NULL
, "localhost", ippPort(), "/printers/%s", name
);
206 snprintf(resource
, sizeof(resource
), "/printers/%s", name
);
208 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
210 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
213 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
215 cupsEncodeOptions2(request
, num_options
, options
, IPP_TAG_OPERATION
);
216 cupsEncodeOptions2(request
, num_options
, options
, IPP_TAG_JOB
);
217 cupsEncodeOptions2(request
, num_options
, options
, IPP_TAG_SUBSCRIPTION
);
220 * Send the request and get the job-id...
223 response
= cupsDoRequest(http
, request
, resource
);
225 if ((attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) != NULL
)
226 job_id
= attr
->values
[0].integer
;
239 * 'cupsFinishDocument()' - Finish sending a document.
241 * The document must have been started using @link cupsStartDocument@.
243 * @since CUPS 1.4/OS X 10.6@
246 ipp_status_t
/* O - Status of document submission */
247 cupsFinishDocument(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
248 const char *name
) /* I - Destination name */
250 char resource
[1024]; /* Printer resource */
253 snprintf(resource
, sizeof(resource
), "/printers/%s", name
);
255 ippDelete(cupsGetResponse(http
, resource
));
257 return (cupsLastError());
262 * 'cupsFreeJobs()' - Free memory used by job data.
266 cupsFreeJobs(int num_jobs
, /* I - Number of jobs */
267 cups_job_t
*jobs
) /* I - Jobs */
269 int i
; /* Looping var */
270 cups_job_t
*job
; /* Current job */
273 if (num_jobs
<= 0 || !jobs
)
276 for (i
= num_jobs
, job
= jobs
; i
> 0; i
--, job
++)
278 _cupsStrFree(job
->dest
);
279 _cupsStrFree(job
->user
);
280 _cupsStrFree(job
->format
);
281 _cupsStrFree(job
->title
);
289 * 'cupsGetClasses()' - Get a list of printer classes from the default server.
291 * This function is deprecated - use @link cupsGetDests@ instead.
296 int /* O - Number of classes */
297 cupsGetClasses(char ***classes
) /* O - Classes */
299 int n
; /* Number of classes */
300 ipp_t
*request
, /* IPP Request */
301 *response
; /* IPP Response */
302 ipp_attribute_t
*attr
; /* Current attribute */
303 char **temp
; /* Temporary pointer */
304 http_t
*http
; /* Connection to server */
309 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
316 if ((http
= _cupsConnect()) == NULL
)
320 * Build a CUPS_GET_CLASSES request, which requires the following
324 * attributes-natural-language
325 * requested-attributes
328 request
= ippNewRequest(IPP_OP_CUPS_GET_CLASSES
);
330 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
331 "requested-attributes", NULL
, "printer-name");
334 * Do the request and get back a response...
339 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
341 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
342 if (attr
->name
!= NULL
&&
343 _cups_strcasecmp(attr
->name
, "printer-name") == 0 &&
344 attr
->value_tag
== IPP_TAG_NAME
)
347 temp
= malloc(sizeof(char *));
349 temp
= realloc(*classes
, sizeof(char *) * (size_t)(n
+ 1));
369 temp
[n
] = strdup(attr
->values
[0].string
.text
);
381 * 'cupsGetDefault()' - Get the default printer or class for the default server.
383 * This function returns the default printer or class as defined by
384 * the LPDEST or PRINTER environment variables. If these environment
385 * variables are not set, the server default destination is returned.
386 * Applications should use the @link cupsGetDests@ and @link cupsGetDest@
387 * functions to get the user-defined default printer, as this function does
388 * not support the lpoptions-defined default printer.
391 const char * /* O - Default printer or @code NULL@ */
395 * Return the default printer...
398 return (cupsGetDefault2(CUPS_HTTP_DEFAULT
));
403 * 'cupsGetDefault2()' - Get the default printer or class for the specified server.
405 * This function returns the default printer or class as defined by
406 * the LPDEST or PRINTER environment variables. If these environment
407 * variables are not set, the server default destination is returned.
408 * Applications should use the @link cupsGetDests@ and @link cupsGetDest@
409 * functions to get the user-defined default printer, as this function does
410 * not support the lpoptions-defined default printer.
412 * @since CUPS 1.1.21/OS X 10.4@
415 const char * /* O - Default printer or @code NULL@ */
416 cupsGetDefault2(http_t
*http
) /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
418 ipp_t
*request
, /* IPP Request */
419 *response
; /* IPP Response */
420 ipp_attribute_t
*attr
; /* Current attribute */
421 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
425 * See if we have a user default printer set...
428 if (_cupsUserDefault(cg
->def_printer
, sizeof(cg
->def_printer
)))
429 return (cg
->def_printer
);
432 * Connect to the server as needed...
436 if ((http
= _cupsConnect()) == NULL
)
440 * Build a CUPS_GET_DEFAULT request, which requires the following
444 * attributes-natural-language
447 request
= ippNewRequest(IPP_OP_CUPS_GET_DEFAULT
);
450 * Do the request and get back a response...
453 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
455 if ((attr
= ippFindAttribute(response
, "printer-name",
456 IPP_TAG_NAME
)) != NULL
)
458 strlcpy(cg
->def_printer
, attr
->values
[0].string
.text
,
459 sizeof(cg
->def_printer
));
461 return (cg
->def_printer
);
472 * 'cupsGetJobs()' - Get the jobs from the default server.
474 * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless
475 * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are
476 * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns
477 * jobs that are stopped, canceled, aborted, or completed.
480 int /* O - Number of jobs */
481 cupsGetJobs(cups_job_t
**jobs
, /* O - Job data */
482 const char *name
, /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */
483 int myjobs
, /* I - 0 = all users, 1 = mine */
484 int whichjobs
) /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */
490 return (cupsGetJobs2(CUPS_HTTP_DEFAULT
, jobs
, name
, myjobs
, whichjobs
));
496 * 'cupsGetJobs2()' - Get the jobs from the specified server.
498 * A "whichjobs" value of @code CUPS_WHICHJOBS_ALL@ returns all jobs regardless
499 * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are
500 * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns
501 * jobs that are stopped, canceled, aborted, or completed.
503 * @since CUPS 1.1.21/OS X 10.4@
506 int /* O - Number of jobs */
507 cupsGetJobs2(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
508 cups_job_t
**jobs
, /* O - Job data */
509 const char *name
, /* I - @code NULL@ = all destinations, otherwise show jobs for named destination */
510 int myjobs
, /* I - 0 = all users, 1 = mine */
511 int whichjobs
) /* I - @code CUPS_WHICHJOBS_ALL@, @code CUPS_WHICHJOBS_ACTIVE@, or @code CUPS_WHICHJOBS_COMPLETED@ */
513 int n
; /* Number of jobs */
514 ipp_t
*request
, /* IPP Request */
515 *response
; /* IPP Response */
516 ipp_attribute_t
*attr
; /* Current attribute */
517 cups_job_t
*temp
; /* Temporary pointer */
519 priority
, /* job-priority */
520 size
; /* job-k-octets */
521 ipp_jstate_t state
; /* job-state */
522 time_t completed_time
, /* time-at-completed */
523 creation_time
, /* time-at-creation */
524 processing_time
; /* time-at-processing */
525 const char *dest
, /* job-printer-uri */
526 *format
, /* document-format */
527 *title
, /* job-name */
528 *user
; /* job-originating-user-name */
529 char uri
[HTTP_MAX_URI
]; /* URI for jobs */
530 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
531 static const char * const attrs
[] = /* Requested attributes */
537 "job-originating-user-name",
548 * Range check input...
553 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
559 * Get the right URI...
564 if (httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
565 "localhost", 0, "/printers/%s",
566 name
) < HTTP_URI_STATUS_OK
)
568 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
569 _("Unable to create printer-uri"), 1);
575 strlcpy(uri
, "ipp://localhost/", sizeof(uri
));
578 if ((http
= _cupsConnect()) == NULL
)
582 * Build an IPP_GET_JOBS request, which requires the following
586 * attributes-natural-language
588 * requesting-user-name
591 * requested-attributes
594 request
= ippNewRequest(IPP_OP_GET_JOBS
);
596 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
597 "printer-uri", NULL
, uri
);
599 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
600 "requesting-user-name", NULL
, cupsUser());
603 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
605 if (whichjobs
== CUPS_WHICHJOBS_COMPLETED
)
606 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
607 "which-jobs", NULL
, "completed");
608 else if (whichjobs
== CUPS_WHICHJOBS_ALL
)
609 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
610 "which-jobs", NULL
, "all");
612 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
613 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
617 * Do the request and get back a response...
623 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
625 for (attr
= response
->attrs
; attr
; attr
= attr
->next
)
628 * Skip leading attributes until we hit a job...
631 while (attr
&& attr
->group_tag
!= IPP_TAG_JOB
)
638 * Pull the needed attributes from this job...
644 state
= IPP_JSTATE_PENDING
;
647 format
= "application/octet-stream";
653 while (attr
&& attr
->group_tag
== IPP_TAG_JOB
)
655 if (!strcmp(attr
->name
, "job-id") &&
656 attr
->value_tag
== IPP_TAG_INTEGER
)
657 id
= attr
->values
[0].integer
;
658 else if (!strcmp(attr
->name
, "job-state") &&
659 attr
->value_tag
== IPP_TAG_ENUM
)
660 state
= (ipp_jstate_t
)attr
->values
[0].integer
;
661 else if (!strcmp(attr
->name
, "job-priority") &&
662 attr
->value_tag
== IPP_TAG_INTEGER
)
663 priority
= attr
->values
[0].integer
;
664 else if (!strcmp(attr
->name
, "job-k-octets") &&
665 attr
->value_tag
== IPP_TAG_INTEGER
)
666 size
= attr
->values
[0].integer
;
667 else if (!strcmp(attr
->name
, "time-at-completed") &&
668 attr
->value_tag
== IPP_TAG_INTEGER
)
669 completed_time
= attr
->values
[0].integer
;
670 else if (!strcmp(attr
->name
, "time-at-creation") &&
671 attr
->value_tag
== IPP_TAG_INTEGER
)
672 creation_time
= attr
->values
[0].integer
;
673 else if (!strcmp(attr
->name
, "time-at-processing") &&
674 attr
->value_tag
== IPP_TAG_INTEGER
)
675 processing_time
= attr
->values
[0].integer
;
676 else if (!strcmp(attr
->name
, "job-printer-uri") &&
677 attr
->value_tag
== IPP_TAG_URI
)
679 if ((dest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
682 else if (!strcmp(attr
->name
, "job-originating-user-name") &&
683 attr
->value_tag
== IPP_TAG_NAME
)
684 user
= attr
->values
[0].string
.text
;
685 else if (!strcmp(attr
->name
, "document-format") &&
686 attr
->value_tag
== IPP_TAG_MIMETYPE
)
687 format
= attr
->values
[0].string
.text
;
688 else if (!strcmp(attr
->name
, "job-name") &&
689 (attr
->value_tag
== IPP_TAG_TEXT
||
690 attr
->value_tag
== IPP_TAG_NAME
))
691 title
= attr
->values
[0].string
.text
;
697 * See if we have everything needed...
709 * Allocate memory for the job...
713 temp
= malloc(sizeof(cups_job_t
));
715 temp
= realloc(*jobs
, sizeof(cups_job_t
) * (size_t)(n
+ 1));
723 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, NULL
, 0);
725 cupsFreeJobs(n
, *jobs
);
738 * Copy the data over...
741 temp
->dest
= _cupsStrAlloc(dest
);
742 temp
->user
= _cupsStrAlloc(user
);
743 temp
->format
= _cupsStrAlloc(format
);
744 temp
->title
= _cupsStrAlloc(title
);
746 temp
->priority
= priority
;
749 temp
->completed_time
= completed_time
;
750 temp
->creation_time
= creation_time
;
751 temp
->processing_time
= processing_time
;
760 if (n
== 0 && cg
->last_error
>= IPP_STATUS_ERROR_BAD_REQUEST
)
768 * 'cupsGetPPD()' - Get the PPD file for a printer on the default server.
770 * For classes, @code cupsGetPPD@ returns the PPD file for the first printer
773 * The returned filename is stored in a static buffer and is overwritten with
774 * each call to @code cupsGetPPD@ or @link cupsGetPPD2@. The caller "owns" the
775 * file that is created and must @code unlink@ the returned filename.
778 const char * /* O - Filename for PPD file */
779 cupsGetPPD(const char *name
) /* I - Destination name */
781 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
782 time_t modtime
= 0; /* Modification time */
786 * Return the PPD file...
789 cg
->ppd_filename
[0] = '\0';
791 if (cupsGetPPD3(CUPS_HTTP_DEFAULT
, name
, &modtime
, cg
->ppd_filename
,
792 sizeof(cg
->ppd_filename
)) == HTTP_STATUS_OK
)
793 return (cg
->ppd_filename
);
800 * 'cupsGetPPD2()' - Get the PPD file for a printer from the specified server.
802 * For classes, @code cupsGetPPD2@ returns the PPD file for the first printer
805 * The returned filename is stored in a static buffer and is overwritten with
806 * each call to @link cupsGetPPD@ or @code cupsGetPPD2@. The caller "owns" the
807 * file that is created and must @code unlink@ the returned filename.
809 * @since CUPS 1.1.21/OS X 10.4@
812 const char * /* O - Filename for PPD file */
813 cupsGetPPD2(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
814 const char *name
) /* I - Destination name */
816 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
817 time_t modtime
= 0; /* Modification time */
820 cg
->ppd_filename
[0] = '\0';
822 if (cupsGetPPD3(http
, name
, &modtime
, cg
->ppd_filename
,
823 sizeof(cg
->ppd_filename
)) == HTTP_STATUS_OK
)
824 return (cg
->ppd_filename
);
831 * 'cupsGetPPD3()' - Get the PPD file for a printer on the specified
832 * server if it has changed.
834 * The "modtime" parameter contains the modification time of any
835 * locally-cached content and is updated with the time from the PPD file on
838 * The "buffer" parameter contains the local PPD filename. If it contains
839 * the empty string, a new temporary file is created, otherwise the existing
840 * file will be overwritten as needed. The caller "owns" the file that is
841 * created and must @code unlink@ the returned filename.
843 * On success, @code HTTP_STATUS_OK@ is returned for a new PPD file and
844 * @code HTTP_STATUS_NOT_MODIFIED@ if the existing PPD file is up-to-date. Any other
845 * status is an error.
847 * For classes, @code cupsGetPPD3@ returns the PPD file for the first printer
850 * @since CUPS 1.4/OS X 10.6@
853 http_status_t
/* O - HTTP status */
854 cupsGetPPD3(http_t
*http
, /* I - HTTP connection or @code CUPS_HTTP_DEFAULT@ */
855 const char *name
, /* I - Destination name */
856 time_t *modtime
, /* IO - Modification time */
857 char *buffer
, /* I - Filename buffer */
858 size_t bufsize
) /* I - Size of filename buffer */
860 int http_port
; /* Port number */
861 char http_hostname
[HTTP_MAX_HOST
];
862 /* Hostname associated with connection */
863 http_t
*http2
; /* Alternate HTTP connection */
864 int fd
; /* PPD file */
865 char localhost
[HTTP_MAX_URI
],/* Local hostname */
866 hostname
[HTTP_MAX_URI
], /* Hostname */
867 resource
[HTTP_MAX_URI
]; /* Resource name */
868 int port
; /* Port number */
869 http_status_t status
; /* HTTP status from server */
870 char tempfile
[1024] = ""; /* Temporary filename */
871 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
875 * Range check input...
878 DEBUG_printf(("cupsGetPPD3(http=%p, name=\"%s\", modtime=%p(%d), buffer=%p, "
879 "bufsize=%d)", http
, name
, modtime
,
880 modtime
? (int)*modtime
: 0, buffer
, (int)bufsize
));
884 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("No printer name"), 1);
885 return (HTTP_STATUS_NOT_ACCEPTABLE
);
890 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("No modification time"), 1);
891 return (HTTP_STATUS_NOT_ACCEPTABLE
);
894 if (!buffer
|| bufsize
<= 1)
896 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Bad filename buffer"), 1);
897 return (HTTP_STATUS_NOT_ACCEPTABLE
);
902 * See if the PPD file is available locally...
906 httpGetHostname(http
, hostname
, sizeof(hostname
));
909 strlcpy(hostname
, cupsServer(), sizeof(hostname
));
910 if (hostname
[0] == '/')
911 strlcpy(hostname
, "localhost", sizeof(hostname
));
914 if (!_cups_strcasecmp(hostname
, "localhost"))
916 char ppdname
[1024]; /* PPD filename */
917 struct stat ppdinfo
; /* PPD file information */
920 snprintf(ppdname
, sizeof(ppdname
), "%s/ppd/%s.ppd", cg
->cups_serverroot
,
922 if (!stat(ppdname
, &ppdinfo
))
925 * OK, the file exists, use it!
932 if (symlink(ppdname
, buffer
) && errno
!= EEXIST
)
934 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, NULL
, 0);
936 return (HTTP_STATUS_SERVER_ERROR
);
941 int tries
; /* Number of tries */
942 const char *tmpdir
; /* TMPDIR environment variable */
943 struct timeval curtime
; /* Current time */
946 * Previously we put root temporary files in the default CUPS temporary
947 * directory under /var/spool/cups. However, since the scheduler cleans
948 * out temporary files there and runs independently of the user apps, we
949 * don't want to use it unless specifically told to by cupsd.
952 if ((tmpdir
= getenv("TMPDIR")) == NULL
)
954 tmpdir
= "/private/tmp"; /* /tmp is a symlink to /private/tmp */
957 # endif /* __APPLE__ */
960 * Make the temporary name using the specified directory...
968 * Get the current time of day...
971 gettimeofday(&curtime
, NULL
);
974 * Format a string using the hex time values...
977 snprintf(buffer
, bufsize
, "%s/%08lx%05lx", tmpdir
,
978 (unsigned long)curtime
.tv_sec
,
979 (unsigned long)curtime
.tv_usec
);
982 * Try to make a symlink...
985 if (!symlink(ppdname
, buffer
))
990 while (tries
< 1000);
994 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, NULL
, 0);
996 return (HTTP_STATUS_SERVER_ERROR
);
1000 if (*modtime
>= ppdinfo
.st_mtime
)
1001 return (HTTP_STATUS_NOT_MODIFIED
);
1004 *modtime
= ppdinfo
.st_mtime
;
1005 return (HTTP_STATUS_OK
);
1012 * Try finding a printer URI for this printer...
1016 if ((http
= _cupsConnect()) == NULL
)
1017 return (HTTP_STATUS_SERVICE_UNAVAILABLE
);
1019 if (!cups_get_printer_uri(http
, name
, hostname
, sizeof(hostname
), &port
,
1020 resource
, sizeof(resource
), 0))
1021 return (HTTP_STATUS_NOT_FOUND
);
1023 DEBUG_printf(("2cupsGetPPD3: Printer hostname=\"%s\", port=%d", hostname
,
1027 * Remap local hostname to localhost...
1030 httpGetHostname(NULL
, localhost
, sizeof(localhost
));
1032 DEBUG_printf(("2cupsGetPPD3: Local hostname=\"%s\"", localhost
));
1034 if (!_cups_strcasecmp(localhost
, hostname
))
1035 strlcpy(hostname
, "localhost", sizeof(hostname
));
1038 * Get the hostname and port number we are connected to...
1041 httpGetHostname(http
, http_hostname
, sizeof(http_hostname
));
1042 http_port
= httpAddrPort(http
->hostaddr
);
1044 DEBUG_printf(("2cupsGetPPD3: Connection hostname=\"%s\", port=%d",
1045 http_hostname
, http_port
));
1048 * Reconnect to the correct server as needed...
1051 if (!_cups_strcasecmp(http_hostname
, hostname
) && port
== http_port
)
1053 else if ((http2
= httpConnect2(hostname
, port
, NULL
, AF_UNSPEC
,
1054 cupsEncryption(), 1, 30000, NULL
)) == NULL
)
1056 DEBUG_puts("1cupsGetPPD3: Unable to connect to server");
1058 return (HTTP_STATUS_SERVICE_UNAVAILABLE
);
1062 * Get a temp file...
1066 fd
= open(buffer
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0600);
1068 fd
= cupsTempFd(tempfile
, sizeof(tempfile
));
1073 * Can't open file; close the server connection and return NULL...
1076 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, NULL
, 0);
1081 return (HTTP_STATUS_SERVER_ERROR
);
1085 * And send a request to the HTTP server...
1088 strlcat(resource
, ".ppd", sizeof(resource
));
1091 httpSetField(http2
, HTTP_FIELD_IF_MODIFIED_SINCE
,
1092 httpGetDateString(*modtime
));
1094 status
= cupsGetFd(http2
, resource
, fd
);
1099 * See if we actually got the file or an error...
1102 if (status
== HTTP_STATUS_OK
)
1104 *modtime
= httpGetDateTime(httpGetField(http2
, HTTP_FIELD_DATE
));
1107 strlcpy(buffer
, tempfile
, bufsize
);
1109 else if (status
!= HTTP_STATUS_NOT_MODIFIED
)
1111 _cupsSetHTTPError(status
);
1115 else if (tempfile
[0])
1118 else if (tempfile
[0])
1125 * Return the PPD file...
1128 DEBUG_printf(("1cupsGetPPD3: Returning status %d", status
));
1135 * 'cupsGetPrinters()' - Get a list of printers from the default server.
1137 * This function is deprecated - use @link cupsGetDests@ instead.
1142 int /* O - Number of printers */
1143 cupsGetPrinters(char ***printers
) /* O - Printers */
1145 int n
; /* Number of printers */
1146 ipp_t
*request
, /* IPP Request */
1147 *response
; /* IPP Response */
1148 ipp_attribute_t
*attr
; /* Current attribute */
1149 char **temp
; /* Temporary pointer */
1150 http_t
*http
; /* Connection to server */
1154 * Range check input...
1159 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
1167 * Try to connect to the server...
1170 if ((http
= _cupsConnect()) == NULL
)
1174 * Build a CUPS_GET_PRINTERS request, which requires the following
1177 * attributes-charset
1178 * attributes-natural-language
1179 * requested-attributes
1182 request
= ippNewRequest(IPP_OP_CUPS_GET_PRINTERS
);
1184 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1185 "requested-attributes", NULL
, "printer-name");
1187 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1190 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_ENUM
,
1191 "printer-type-mask", CUPS_PRINTER_CLASS
);
1194 * Do the request and get back a response...
1199 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1201 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1202 if (attr
->name
!= NULL
&&
1203 _cups_strcasecmp(attr
->name
, "printer-name") == 0 &&
1204 attr
->value_tag
== IPP_TAG_NAME
)
1207 temp
= malloc(sizeof(char *));
1209 temp
= realloc(*printers
, sizeof(char *) * (size_t)(n
+ 1));
1214 * Ran out of memory!
1220 free((*printers
)[n
]);
1224 ippDelete(response
);
1229 temp
[n
] = strdup(attr
->values
[0].string
.text
);
1233 ippDelete(response
);
1241 * 'cupsGetServerPPD()' - Get an available PPD file from the server.
1243 * This function returns the named PPD file from the server. The
1244 * list of available PPDs is provided by the IPP @code CUPS_GET_PPDS@
1247 * You must remove (unlink) the PPD file when you are finished with
1248 * it. The PPD filename is stored in a static location that will be
1249 * overwritten on the next call to @link cupsGetPPD@, @link cupsGetPPD2@,
1250 * or @link cupsGetServerPPD@.
1252 * @since CUPS 1.3/OS X 10.5@
1255 char * /* O - Name of PPD file or @code NULL@ on error */
1256 cupsGetServerPPD(http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
1257 const char *name
) /* I - Name of PPD file ("ppd-name") */
1259 int fd
; /* PPD file descriptor */
1260 ipp_t
*request
; /* IPP request */
1261 _cups_globals_t
*cg
= _cupsGlobals();
1262 /* Pointer to library globals */
1266 * Range check input...
1271 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("No PPD name"), 1);
1277 if ((http
= _cupsConnect()) == NULL
)
1281 * Get a temp file...
1284 if ((fd
= cupsTempFd(cg
->ppd_filename
, sizeof(cg
->ppd_filename
))) < 0)
1287 * Can't open file; close the server connection and return NULL...
1290 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, NULL
, 0);
1296 * Get the PPD file...
1299 request
= ippNewRequest(IPP_OP_CUPS_GET_PPD
);
1300 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "ppd-name", NULL
,
1303 ippDelete(cupsDoIORequest(http
, request
, "/", -1, fd
));
1307 if (cupsLastError() != IPP_STATUS_OK
)
1309 unlink(cg
->ppd_filename
);
1313 return (cg
->ppd_filename
);
1318 * 'cupsPrintFile()' - Print a file to a printer or class on the default server.
1321 int /* O - Job ID or 0 on error */
1322 cupsPrintFile(const char *name
, /* I - Destination name */
1323 const char *filename
, /* I - File to print */
1324 const char *title
, /* I - Title of job */
1325 int num_options
,/* I - Number of options */
1326 cups_option_t
*options
) /* I - Options */
1328 DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
1329 "title=\"%s\", num_options=%d, options=%p)",
1330 name
, filename
, title
, num_options
, options
));
1332 return (cupsPrintFiles2(CUPS_HTTP_DEFAULT
, name
, 1, &filename
, title
,
1333 num_options
, options
));
1338 * 'cupsPrintFile2()' - Print a file to a printer or class on the specified
1341 * @since CUPS 1.1.21/OS X 10.4@
1344 int /* O - Job ID or 0 on error */
1346 http_t
*http
, /* I - Connection to server */
1347 const char *name
, /* I - Destination name */
1348 const char *filename
, /* I - File to print */
1349 const char *title
, /* I - Title of job */
1350 int num_options
, /* I - Number of options */
1351 cups_option_t
*options
) /* I - Options */
1353 DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", "
1354 "title=\"%s\", num_options=%d, options=%p)",
1355 http
, name
, filename
, title
, num_options
, options
));
1357 return (cupsPrintFiles2(http
, name
, 1, &filename
, title
, num_options
,
1363 * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
1367 int /* O - Job ID or 0 on error */
1369 const char *name
, /* I - Destination name */
1370 int num_files
, /* I - Number of files */
1371 const char **files
, /* I - File(s) to print */
1372 const char *title
, /* I - Title of job */
1373 int num_options
, /* I - Number of options */
1374 cups_option_t
*options
) /* I - Options */
1376 DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, "
1377 "files=%p, title=\"%s\", num_options=%d, options=%p)",
1378 name
, num_files
, files
, title
, num_options
, options
));
1381 * Print the file(s)...
1384 return (cupsPrintFiles2(CUPS_HTTP_DEFAULT
, name
, num_files
, files
, title
,
1385 num_options
, options
));
1390 * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
1393 * @since CUPS 1.1.21/OS X 10.4@
1396 int /* O - Job ID or 0 on error */
1398 http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
1399 const char *name
, /* I - Destination name */
1400 int num_files
, /* I - Number of files */
1401 const char **files
, /* I - File(s) to print */
1402 const char *title
, /* I - Title of job */
1403 int num_options
, /* I - Number of options */
1404 cups_option_t
*options
) /* I - Options */
1406 int i
; /* Looping var */
1407 int job_id
; /* New job ID */
1408 const char *docname
; /* Basename of current filename */
1409 const char *format
; /* Document format */
1410 cups_file_t
*fp
; /* Current file */
1411 char buffer
[8192]; /* Copy buffer */
1412 ssize_t bytes
; /* Bytes in buffer */
1413 http_status_t status
; /* Status of write */
1414 _cups_globals_t
*cg
= _cupsGlobals(); /* Global data */
1415 ipp_status_t cancel_status
; /* Status code to preserve */
1416 char *cancel_message
; /* Error message to preserve */
1419 DEBUG_printf(("cupsPrintFiles2(http=%p, name=\"%s\", num_files=%d, "
1420 "files=%p, title=\"%s\", num_options=%d, options=%p)",
1421 http
, name
, num_files
, files
, title
, num_options
, options
));
1424 * Range check input...
1427 if (!name
|| num_files
< 1 || !files
)
1429 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(EINVAL
), 0);
1435 * Create the print job...
1438 if ((job_id
= cupsCreateJob(http
, name
, title
, num_options
, options
)) == 0)
1442 * Send each of the files...
1445 if (cupsGetOption("raw", num_options
, options
))
1446 format
= CUPS_FORMAT_RAW
;
1447 else if ((format
= cupsGetOption("document-format", num_options
,
1449 format
= CUPS_FORMAT_AUTO
;
1451 for (i
= 0; i
< num_files
; i
++)
1454 * Start the next file...
1457 if ((docname
= strrchr(files
[i
], '/')) != NULL
)
1462 if ((fp
= cupsFileOpen(files
[i
], "rb")) == NULL
)
1465 * Unable to open print file, cancel the job and return...
1468 _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_ACCESS
, NULL
, 0);
1472 status
= cupsStartDocument(http
, name
, job_id
, docname
, format
,
1473 i
== (num_files
- 1));
1475 while (status
== HTTP_STATUS_CONTINUE
&&
1476 (bytes
= cupsFileRead(fp
, buffer
, sizeof(buffer
))) > 0)
1477 status
= cupsWriteRequestData(http
, buffer
, (size_t)bytes
);
1481 if (status
!= HTTP_STATUS_CONTINUE
|| cupsFinishDocument(http
, name
) != IPP_STATUS_OK
)
1484 * Unable to queue, cancel the job and return...
1494 * If we get here, something happened while sending the print job so we need
1495 * to cancel the job without setting the last error (since we need to preserve
1496 * the current error...
1501 cancel_status
= cg
->last_error
;
1502 cancel_message
= cg
->last_status_message
?
1503 _cupsStrRetain(cg
->last_status_message
) : NULL
;
1505 cupsCancelJob2(http
, name
, job_id
, 0);
1507 cg
->last_error
= cancel_status
;
1508 cg
->last_status_message
= cancel_message
;
1515 * 'cupsStartDocument()' - Add a document to a job created with cupsCreateJob().
1517 * Use @link cupsWriteRequestData@ to write data for the document and
1518 * @link cupsFinishDocument@ to finish the document and get the submission status.
1520 * The MIME type constants @code CUPS_FORMAT_AUTO@, @code CUPS_FORMAT_PDF@,
1521 * @code CUPS_FORMAT_POSTSCRIPT@, @code CUPS_FORMAT_RAW@, and
1522 * @code CUPS_FORMAT_TEXT@ are provided for the "format" argument, although
1523 * any supported MIME type string can be supplied.
1525 * @since CUPS 1.4/OS X 10.6@
1528 http_status_t
/* O - HTTP status of request */
1530 http_t
*http
, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
1531 const char *name
, /* I - Destination name */
1532 int job_id
, /* I - Job ID from @link cupsCreateJob@ */
1533 const char *docname
, /* I - Name of document */
1534 const char *format
, /* I - MIME type or @code CUPS_FORMAT_foo@ */
1535 int last_document
) /* I - 1 for last document in job, 0 otherwise */
1537 char resource
[1024], /* Resource for destinatio */
1538 printer_uri
[1024]; /* Printer URI */
1539 ipp_t
*request
; /* Send-Document request */
1540 http_status_t status
; /* HTTP status */
1544 * Create a Send-Document request...
1547 if ((request
= ippNewRequest(IPP_OP_SEND_DOCUMENT
)) == NULL
)
1549 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, strerror(ENOMEM
), 0);
1550 return (HTTP_STATUS_ERROR
);
1553 httpAssembleURIf(HTTP_URI_CODING_ALL
, printer_uri
, sizeof(printer_uri
), "ipp",
1554 NULL
, "localhost", ippPort(), "/printers/%s", name
);
1555 snprintf(resource
, sizeof(resource
), "/printers/%s", name
);
1557 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1559 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", job_id
);
1560 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1563 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "document-name",
1566 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
,
1567 "document-format", NULL
, format
);
1568 ippAddBoolean(request
, IPP_TAG_OPERATION
, "last-document", (char)last_document
);
1571 * Send and delete the request, then return the status...
1574 status
= cupsSendRequest(http
, request
, resource
, CUPS_LENGTH_VARIABLE
);
1583 * 'cups_get_printer_uri()' - Get the printer-uri-supported attribute for the
1584 * first printer in a class.
1587 static int /* O - 1 on success, 0 on failure */
1588 cups_get_printer_uri(
1589 http_t
*http
, /* I - Connection to server */
1590 const char *name
, /* I - Name of printer or class */
1591 char *host
, /* I - Hostname buffer */
1592 int hostsize
, /* I - Size of hostname buffer */
1593 int *port
, /* O - Port number */
1594 char *resource
, /* I - Resource buffer */
1595 int resourcesize
, /* I - Size of resource buffer */
1596 int depth
) /* I - Depth of query */
1598 int i
; /* Looping var */
1599 int http_port
; /* Port number */
1600 http_t
*http2
; /* Alternate HTTP connection */
1601 ipp_t
*request
, /* IPP request */
1602 *response
; /* IPP response */
1603 ipp_attribute_t
*attr
; /* Current attribute */
1604 char uri
[HTTP_MAX_URI
], /* printer-uri attribute */
1605 scheme
[HTTP_MAX_URI
], /* Scheme name */
1606 username
[HTTP_MAX_URI
], /* Username:password */
1607 classname
[255], /* Temporary class name */
1608 http_hostname
[HTTP_MAX_HOST
];
1609 /* Hostname associated with connection */
1610 static const char * const requested_attrs
[] =
1611 { /* Requested attributes */
1614 "printer-uri-supported",
1619 DEBUG_printf(("7cups_get_printer_uri(http=%p, name=\"%s\", host=%p, "
1620 "hostsize=%d, resource=%p, resourcesize=%d, depth=%d)",
1621 http
, name
, host
, hostsize
, resource
, resourcesize
, depth
));
1624 * Setup the printer URI...
1627 if (httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
1628 "localhost", 0, "/printers/%s",
1629 name
) < HTTP_URI_STATUS_OK
)
1631 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("Unable to create printer-uri"),
1640 DEBUG_printf(("9cups_get_printer_uri: printer-uri=\"%s\"", uri
));
1643 * Get the hostname and port number we are connected to...
1646 httpGetHostname(http
, http_hostname
, sizeof(http_hostname
));
1647 http_port
= httpAddrPort(http
->hostaddr
);
1650 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1653 * attributes-charset
1654 * attributes-natural-language
1656 * requested-attributes
1659 request
= ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES
);
1661 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1664 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1665 "requested-attributes",
1666 sizeof(requested_attrs
) / sizeof(requested_attrs
[0]),
1667 NULL
, requested_attrs
);
1670 * Do the request and get back a response...
1673 snprintf(resource
, resourcesize
, "/printers/%s", name
);
1675 if ((response
= cupsDoRequest(http
, request
, resource
)) != NULL
)
1677 const char *device_uri
= NULL
; /* device-uri value */
1679 if ((attr
= ippFindAttribute(response
, "device-uri",
1680 IPP_TAG_URI
)) != NULL
)
1681 device_uri
= attr
->values
[0].string
.text
;
1684 (!strncmp(device_uri
, "ipp://", 6) ||
1685 !strncmp(device_uri
, "ipps://", 7) ||
1686 ((strstr(device_uri
, "._ipp.") != NULL
||
1687 strstr(device_uri
, "._ipps.") != NULL
) &&
1688 !strcmp(device_uri
+ strlen(device_uri
) - 5, "/cups"))))
1691 * Statically-configured shared printer.
1694 httpSeparateURI(HTTP_URI_CODING_ALL
,
1695 _httpResolveURI(device_uri
, uri
, sizeof(uri
),
1696 _HTTP_RESOLVE_DEFAULT
, NULL
, NULL
),
1697 scheme
, sizeof(scheme
), username
, sizeof(username
),
1698 host
, hostsize
, port
, resource
, resourcesize
);
1699 ippDelete(response
);
1703 else if ((attr
= ippFindAttribute(response
, "member-uris",
1704 IPP_TAG_URI
)) != NULL
)
1707 * Get the first actual printer name in the class...
1710 for (i
= 0; i
< attr
->num_values
; i
++)
1712 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[i
].string
.text
,
1713 scheme
, sizeof(scheme
), username
, sizeof(username
),
1714 host
, hostsize
, port
, resource
, resourcesize
);
1715 if (!strncmp(resource
, "/printers/", 10))
1721 ippDelete(response
);
1728 * No printers in this class - try recursively looking for a printer,
1729 * but not more than 3 levels deep...
1734 for (i
= 0; i
< attr
->num_values
; i
++)
1736 httpSeparateURI(HTTP_URI_CODING_ALL
, attr
->values
[i
].string
.text
,
1737 scheme
, sizeof(scheme
), username
, sizeof(username
),
1738 host
, hostsize
, port
, resource
, resourcesize
);
1739 if (!strncmp(resource
, "/classes/", 9))
1742 * Found a class! Connect to the right server...
1745 if (!_cups_strcasecmp(http_hostname
, host
) && *port
== http_port
)
1747 else if ((http2
= httpConnect2(host
, *port
, NULL
, AF_UNSPEC
,
1748 cupsEncryption(), 1, 30000,
1751 DEBUG_puts("8cups_get_printer_uri: Unable to connect to server");
1757 * Look up printers on that server...
1760 strlcpy(classname
, resource
+ 9, sizeof(classname
));
1762 cups_get_printer_uri(http2
, classname
, host
, hostsize
, port
,
1763 resource
, resourcesize
, depth
+ 1);
1766 * Close the connection as needed...
1778 else if ((attr
= ippFindAttribute(response
, "printer-uri-supported",
1779 IPP_TAG_URI
)) != NULL
)
1781 httpSeparateURI(HTTP_URI_CODING_ALL
,
1782 _httpResolveURI(attr
->values
[0].string
.text
, uri
,
1783 sizeof(uri
), _HTTP_RESOLVE_DEFAULT
,
1785 scheme
, sizeof(scheme
), username
, sizeof(username
),
1786 host
, hostsize
, port
, resource
, resourcesize
);
1787 ippDelete(response
);
1789 if (!strncmp(resource
, "/classes/", 9))
1791 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
1792 _("No printer-uri found for class"), 1);
1803 ippDelete(response
);
1806 if (cupsLastError() != IPP_STATUS_ERROR_NOT_FOUND
)
1807 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("No printer-uri found"), 1);