4 * Printing utilities for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2005 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * cupsCancelJob() - Cancel a print job.
29 * cupsDoFileRequest() - Do an IPP request...
30 * cupsFreeJobs() - Free memory used by job data.
31 * cupsGetClasses() - Get a list of printer classes.
32 * cupsGetDefault() - Get the default printer or class.
33 * cupsGetDefault2() - Get the default printer or class.
34 * cupsGetJobs() - Get the jobs from the server.
35 * cupsGetJobs2() - Get the jobs from the server.
36 * cupsGetPPD() - Get the PPD file for a printer.
37 * cupsGetPPD2() - Get the PPD file for a printer.
38 * cupsGetPrinters() - Get a list of printers.
39 * cupsLastError() - Return the last IPP error that occurred.
40 * cupsPrintFile() - Print a file to a printer or class.
41 * cupsPrintFile2() - Print a file to a printer or class.
42 * cupsPrintFiles() - Print one or more files to a printer or class.
43 * cupsPrintFiles2() - Print one or more files to a printer or class.
44 * cups_connect() - Connect to the specified host...
48 * Include necessary headers...
57 #if defined(WIN32) || defined(__EMX__)
61 #endif /* WIN32 || __EMX__ */
68 static char *cups_connect(const char *name
, char *printer
, char *hostname
);
72 * 'cupsCancelJob()' - Cancel a print job.
75 int /* O - 1 on success, 0 on failure */
76 cupsCancelJob(const char *name
, /* I - Name of printer or class */
77 int job
) /* I - Job ID */
79 char printer
[HTTP_MAX_URI
], /* Printer name */
80 hostname
[HTTP_MAX_URI
], /* Hostname */
81 uri
[HTTP_MAX_URI
]; /* Printer URI */
82 ipp_t
*request
, /* IPP request */
83 *response
; /* IPP response */
84 cups_lang_t
*language
; /* Language info */
85 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
89 * See if we can connect to the server...
92 if (!cups_connect(name
, printer
, hostname
))
94 DEBUG_puts("Unable to connect to server!");
95 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
100 * Build an IPP_CANCEL_JOB request, which requires the following
104 * attributes-natural-language
107 * [requesting-user-name]
112 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
113 request
->request
.op
.request_id
= 1;
115 language
= cupsLangDefault();
117 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
118 "attributes-charset", NULL
, cupsLangEncoding(language
));
120 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
121 "attributes-natural-language", NULL
,
122 language
!= NULL
? language
->language
: "C");
124 cupsLangFree(language
);
126 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/printers/%s", hostname
, ippPort(), printer
);
127 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
130 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", job
);
132 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
139 if ((response
= cupsDoRequest(cg
->http
, request
, "/jobs/")) != NULL
)
142 return (cg
->last_error
< IPP_REDIRECTION_OTHER_SITE
);
147 * 'cupsDoFileRequest()' - Do an IPP request...
150 ipp_t
* /* O - Response data */
151 cupsDoFileRequest(http_t
*http
, /* I - HTTP connection to server */
152 ipp_t
*request
, /* I - IPP request */
153 const char *resource
, /* I - HTTP resource for POST */
154 const char *filename
) /* I - File to send or NULL */
156 ipp_t
*response
; /* IPP response data */
157 char length
[255]; /* Content-Length field */
158 http_status_t status
; /* Status of HTTP request */
159 FILE *file
; /* File to send */
160 struct stat fileinfo
; /* File information */
161 int bytes
; /* Number of bytes read/written */
162 char buffer
[32768]; /* Output buffer */
163 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
166 DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
167 http
, request
, resource
? resource
: "(null)",
168 filename
? filename
: "(null)"));
170 if (http
== NULL
|| request
== NULL
|| resource
== NULL
)
175 cg
->last_error
= IPP_INTERNAL_ERROR
;
180 * See if we have a file to send...
183 if (filename
!= NULL
)
185 if (stat(filename
, &fileinfo
))
188 * Can't get file information!
192 cg
->last_error
= IPP_NOT_FOUND
;
197 if (fileinfo
.st_mode
& _S_IFDIR
)
199 if (S_ISDIR(fileinfo
.st_mode
))
203 * Can't send a directory...
207 cg
->last_error
= IPP_NOT_POSSIBLE
;
211 if ((file
= fopen(filename
, "rb")) == NULL
)
218 cg
->last_error
= IPP_NOT_FOUND
;
226 * Loop until we can send the request without authorization problems.
232 while (response
== NULL
)
234 DEBUG_puts("cupsDoFileRequest: setup...");
237 * Setup the HTTP variables needed...
240 if (filename
!= NULL
)
241 sprintf(length
, "%lu", (unsigned long)(ippLength(request
) +
242 (size_t)fileinfo
.st_size
));
244 sprintf(length
, "%lu", (unsigned long)ippLength(request
));
246 httpClearFields(http
);
247 httpSetField(http
, HTTP_FIELD_CONTENT_LENGTH
, length
);
248 httpSetField(http
, HTTP_FIELD_CONTENT_TYPE
, "application/ipp");
249 httpSetField(http
, HTTP_FIELD_AUTHORIZATION
, http
->authstring
);
251 DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http
->authstring
));
257 DEBUG_puts("cupsDoFileRequest: post...");
259 if (httpPost(http
, resource
))
261 if (httpReconnect(http
))
271 * Send the IPP data and wait for the response...
274 DEBUG_puts("cupsDoFileRequest: ipp write...");
276 request
->state
= IPP_IDLE
;
277 status
= HTTP_CONTINUE
;
279 if (ippWrite(http
, request
) != IPP_ERROR
)
280 if (filename
!= NULL
)
282 DEBUG_puts("cupsDoFileRequest: file write...");
290 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), file
)) > 0)
294 if ((status
= httpUpdate(http
)) != HTTP_CONTINUE
)
298 if (httpWrite(http
, buffer
, bytes
) < bytes
)
304 * Get the server's return status...
307 DEBUG_puts("cupsDoFileRequest: update...");
309 while (status
== HTTP_CONTINUE
)
310 status
= httpUpdate(http
);
312 DEBUG_printf(("cupsDoFileRequest: status = %d\n", status
));
314 if (status
== HTTP_UNAUTHORIZED
)
316 DEBUG_puts("cupsDoFileRequest: unauthorized...");
319 * Flush any error message...
325 * See if we can do authentication...
328 if (cupsDoAuthentication(http
, "POST", resource
))
335 else if (status
== HTTP_ERROR
)
338 if (http
->error
!= WSAENETDOWN
&& http
->error
!= WSAENETUNREACH
)
340 if (http
->error
!= ENETDOWN
&& http
->error
!= ENETUNREACH
)
347 else if (status
== HTTP_UPGRADE_REQUIRED
)
349 /* Flush any error message... */
353 if (httpReconnect(http
))
359 /* Upgrade with encryption... */
360 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
362 /* Try again, this time with encryption enabled... */
365 #endif /* HAVE_SSL */
366 else if (status
!= HTTP_OK
)
368 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status
));
371 * Flush any error message...
380 * Read the response...
383 DEBUG_puts("cupsDoFileRequest: response...");
387 if (ippRead(http
, response
) == IPP_ERROR
)
390 * Delete the response...
393 DEBUG_puts("IPP read error!");
397 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
404 * Close the file if needed...
407 if (filename
!= NULL
)
411 * Flush any remaining data...
417 * Delete the original request and return the response...
423 cg
->last_error
= response
->request
.status
.status_code
;
424 else if (status
!= HTTP_OK
)
428 case HTTP_NOT_FOUND
:
429 cg
->last_error
= IPP_NOT_FOUND
;
432 case HTTP_UNAUTHORIZED
:
433 cg
->last_error
= IPP_NOT_AUTHORIZED
;
436 case HTTP_FORBIDDEN
:
437 cg
->last_error
= IPP_FORBIDDEN
;
440 case HTTP_BAD_REQUEST
:
441 cg
->last_error
= IPP_BAD_REQUEST
;
444 case HTTP_REQUEST_TOO_LARGE
:
445 cg
->last_error
= IPP_REQUEST_VALUE
;
448 case HTTP_NOT_IMPLEMENTED
:
449 cg
->last_error
= IPP_OPERATION_NOT_SUPPORTED
;
452 case HTTP_NOT_SUPPORTED
:
453 cg
->last_error
= IPP_VERSION_NOT_SUPPORTED
;
457 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
459 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
469 * 'cupsFreeJobs()' - Free memory used by job data.
473 cupsFreeJobs(int num_jobs
, /* I - Number of jobs */
474 cups_job_t
*jobs
) /* I - Jobs */
476 int i
; /* Looping var */
479 if (num_jobs
<= 0 || jobs
== NULL
)
482 for (i
= 0; i
< num_jobs
; i
++)
486 free(jobs
[i
].format
);
495 * 'cupsGetClasses()' - Get a list of printer classes.
498 int /* O - Number of classes */
499 cupsGetClasses(char ***classes
) /* O - Classes */
501 int n
; /* Number of classes */
502 ipp_t
*request
, /* IPP Request */
503 *response
; /* IPP Response */
504 ipp_attribute_t
*attr
; /* Current attribute */
505 cups_lang_t
*language
; /* Default language */
506 char **temp
; /* Temporary pointer */
507 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
512 cg
->last_error
= IPP_INTERNAL_ERROR
;
517 * Try to connect to the server...
520 if (!cups_connect("default", NULL
, NULL
))
522 DEBUG_puts("Unable to connect to server!");
523 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
528 * Build a CUPS_GET_CLASSES request, which requires the following
532 * attributes-natural-language
533 * requested-attributes
538 request
->request
.op
.operation_id
= CUPS_GET_CLASSES
;
539 request
->request
.op
.request_id
= 1;
541 language
= cupsLangDefault();
543 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
544 "attributes-charset", NULL
, cupsLangEncoding(language
));
546 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
547 "attributes-natural-language", NULL
, language
->language
);
549 cupsLangFree(language
);
551 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
552 "requested-attributes", NULL
, "printer-name");
555 * Do the request and get back a response...
561 if ((response
= cupsDoRequest(cg
->http
, request
, "/")) != NULL
)
563 cg
->last_error
= response
->request
.status
.status_code
;
565 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
566 if (attr
->name
!= NULL
&&
567 strcasecmp(attr
->name
, "printer-name") == 0 &&
568 attr
->value_tag
== IPP_TAG_NAME
)
571 temp
= malloc(sizeof(char *));
573 temp
= realloc(*classes
, sizeof(char *) * (n
+ 1));
593 temp
[n
] = strdup(attr
->values
[0].string
.text
);
600 cg
->last_error
= IPP_BAD_REQUEST
;
607 * 'cupsGetDefault()' - Get the default printer or class.
610 const char * /* O - Default printer or NULL */
613 const char *var
; /* Environment variable */
614 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
618 * First see if the LPDEST or PRINTER environment variables are
619 * set... However, if PRINTER is set to "lp", ignore it to work
620 * around a "feature" in most Linux distributions - the default
621 * user login scripts set PRINTER to "lp"...
624 if ((var
= getenv("LPDEST")) != NULL
)
626 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
630 * Try to connect to the server...
633 if (!cups_connect("default", NULL
, NULL
))
635 DEBUG_puts("Unable to connect to server!");
636 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
641 * Return the default printer...
644 return (cupsGetDefault2(cg
->http
));
649 * 'cupsGetDefault2()' - Get the default printer or class.
652 const char * /* O - Default printer or NULL */
653 cupsGetDefault2(http_t
*http
) /* I - HTTP connection */
655 ipp_t
*request
, /* IPP Request */
656 *response
; /* IPP Response */
657 ipp_attribute_t
*attr
; /* Current attribute */
658 cups_lang_t
*language
; /* Default language */
659 const char *var
; /* Environment variable */
660 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
664 * First see if the LPDEST or PRINTER environment variables are
665 * set... However, if PRINTER is set to "lp", ignore it to work
666 * around a "feature" in most Linux distributions - the default
667 * user login scripts set PRINTER to "lp"...
670 if ((var
= getenv("LPDEST")) != NULL
)
672 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
676 * Range check input...
683 * Build a CUPS_GET_DEFAULT request, which requires the following
687 * attributes-natural-language
692 request
->request
.op
.operation_id
= CUPS_GET_DEFAULT
;
693 request
->request
.op
.request_id
= 1;
695 language
= cupsLangDefault();
697 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
698 "attributes-charset", NULL
, cupsLangEncoding(language
));
700 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
701 "attributes-natural-language", NULL
, language
->language
);
703 cupsLangFree(language
);
706 * Do the request and get back a response...
709 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
711 cg
->last_error
= response
->request
.status
.status_code
;
713 if ((attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
)) != NULL
)
715 strlcpy(cg
->def_printer
, attr
->values
[0].string
.text
, sizeof(cg
->def_printer
));
717 return (cg
->def_printer
);
723 cg
->last_error
= IPP_BAD_REQUEST
;
730 * 'cupsGetJobs()' - Get the jobs from the server.
733 int /* O - Number of jobs */
734 cupsGetJobs(cups_job_t
**jobs
, /* O - Job data */
735 const char *mydest
, /* I - Only show jobs for dest? */
736 int myjobs
, /* I - Only show my jobs? */
737 int completed
) /* I - Only show completed jobs? */
739 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
742 * Try to connect to the server...
745 if (!cups_connect("default", NULL
, NULL
))
747 DEBUG_puts("Unable to connect to server!");
748 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
756 return (cupsGetJobs2(cg
->http
, jobs
, mydest
, myjobs
, completed
));
762 * 'cupsGetJobs2()' - Get the jobs from the server.
765 int /* O - Number of jobs */
766 cupsGetJobs2(http_t
*http
, /* I - HTTP connection */
767 cups_job_t
**jobs
, /* O - Job data */
768 const char *mydest
, /* I - Only show jobs for dest? */
769 int myjobs
, /* I - Only show my jobs? */
770 int completed
) /* I - Only show completed jobs? */
772 int n
; /* Number of jobs */
773 ipp_t
*request
, /* IPP Request */
774 *response
; /* IPP Response */
775 ipp_attribute_t
*attr
; /* Current attribute */
776 cups_lang_t
*language
; /* Default language */
777 cups_job_t
*temp
; /* Temporary pointer */
779 priority
, /* job-priority */
780 size
; /* job-k-octets */
781 ipp_jstate_t state
; /* job-state */
782 time_t completed_time
, /* time-at-completed */
783 creation_time
, /* time-at-creation */
784 processing_time
; /* time-at-processing */
785 const char *dest
, /* job-printer-uri */
786 *format
, /* document-format */
787 *title
, /* job-name */
788 *user
; /* job-originating-user-name */
789 char uri
[HTTP_MAX_URI
]; /* URI for jobs */
790 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
791 static const char * const attrs
[] = /* Requested attributes */
799 "time-at-processing",
803 "job-originating-user-name"
809 cg
->last_error
= IPP_INTERNAL_ERROR
;
814 * Build an IPP_GET_JOBS request, which requires the following
818 * attributes-natural-language
820 * requesting-user-name
823 * requested-attributes
828 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
829 request
->request
.op
.request_id
= 1;
831 language
= cupsLangDefault();
833 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
834 "attributes-charset", NULL
, cupsLangEncoding(language
));
836 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
837 "attributes-natural-language", NULL
, language
->language
);
839 cupsLangFree(language
);
842 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", mydest
);
844 strcpy(uri
, "ipp://localhost/jobs");
846 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
847 "printer-uri", NULL
, uri
);
849 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
850 "requesting-user-name", NULL
, cupsUser());
853 ippAddBoolean(request
, IPP_TAG_OPERATION
, "my-jobs", 1);
856 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
857 "which-jobs", NULL
, "completed");
859 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
860 "requested-attributes", sizeof(attrs
) / sizeof(attrs
[0]),
864 * Do the request and get back a response...
870 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
872 cg
->last_error
= response
->request
.status
.status_code
;
874 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
877 * Skip leading attributes until we hit a job...
880 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
887 * Pull the needed attributes from this job...
893 state
= IPP_JOB_PENDING
;
896 format
= "application/octet-stream";
902 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
)
904 if (strcmp(attr
->name
, "job-id") == 0 &&
905 attr
->value_tag
== IPP_TAG_INTEGER
)
906 id
= attr
->values
[0].integer
;
907 else if (strcmp(attr
->name
, "job-state") == 0 &&
908 attr
->value_tag
== IPP_TAG_ENUM
)
909 state
= (ipp_jstate_t
)attr
->values
[0].integer
;
910 else if (strcmp(attr
->name
, "job-priority") == 0 &&
911 attr
->value_tag
== IPP_TAG_INTEGER
)
912 priority
= attr
->values
[0].integer
;
913 else if (strcmp(attr
->name
, "job-k-octets") == 0 &&
914 attr
->value_tag
== IPP_TAG_INTEGER
)
915 size
= attr
->values
[0].integer
;
916 else if (strcmp(attr
->name
, "time-at-completed") == 0 &&
917 attr
->value_tag
== IPP_TAG_INTEGER
)
918 completed_time
= attr
->values
[0].integer
;
919 else if (strcmp(attr
->name
, "time-at-creation") == 0 &&
920 attr
->value_tag
== IPP_TAG_INTEGER
)
921 creation_time
= attr
->values
[0].integer
;
922 else if (strcmp(attr
->name
, "time-at-processing") == 0 &&
923 attr
->value_tag
== IPP_TAG_INTEGER
)
924 processing_time
= attr
->values
[0].integer
;
925 else if (strcmp(attr
->name
, "job-printer-uri") == 0 &&
926 attr
->value_tag
== IPP_TAG_URI
)
928 if ((dest
= strrchr(attr
->values
[0].string
.text
, '/')) != NULL
)
931 else if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
932 attr
->value_tag
== IPP_TAG_NAME
)
933 user
= attr
->values
[0].string
.text
;
934 else if (strcmp(attr
->name
, "document-format") == 0 &&
935 attr
->value_tag
== IPP_TAG_MIMETYPE
)
936 format
= attr
->values
[0].string
.text
;
937 else if (strcmp(attr
->name
, "job-name") == 0 &&
938 (attr
->value_tag
== IPP_TAG_TEXT
||
939 attr
->value_tag
== IPP_TAG_NAME
))
940 title
= attr
->values
[0].string
.text
;
946 * See if we have everything needed...
949 if (dest
== NULL
|| id
== 0)
958 * Allocate memory for the job...
962 temp
= malloc(sizeof(cups_job_t
));
964 temp
= realloc(*jobs
, sizeof(cups_job_t
) * (n
+ 1));
972 cupsFreeJobs(n
, *jobs
);
984 * Copy the data over...
987 temp
->dest
= strdup(dest
);
988 temp
->user
= strdup(user
);
989 temp
->format
= strdup(format
);
990 temp
->title
= strdup(title
);
992 temp
->priority
= priority
;
995 temp
->completed_time
= completed_time
;
996 temp
->creation_time
= creation_time
;
997 temp
->processing_time
= processing_time
;
1003 ippDelete(response
);
1006 cg
->last_error
= IPP_BAD_REQUEST
;
1008 if (n
== 0 && cg
->last_error
>= IPP_BAD_REQUEST
)
1016 * 'cupsGetPPD()' - Get the PPD file for a printer.
1019 const char * /* O - Filename for PPD file */
1020 cupsGetPPD(const char *name
) /* I - Printer name */
1022 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1025 * See if we can connect to the server...
1028 if (!cups_connect(name
, NULL
, NULL
))
1030 DEBUG_puts("Unable to connect to server!");
1031 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1036 * Return the PPD file...
1039 return (cupsGetPPD2(cg
->http
, name
));
1044 * 'cupsGetPPD2()' - Get the PPD file for a printer.
1047 const char * /* O - Filename for PPD file */
1048 cupsGetPPD2(http_t
*http
, /* I - HTTP connection */
1049 const char *name
) /* I - Printer name */
1051 int i
; /* Looping var */
1052 http_t
*http2
; /* Alternate HTTP connection */
1053 ipp_t
*request
, /* IPP request */
1054 *response
; /* IPP response */
1055 ipp_attribute_t
*attr
; /* Current attribute */
1056 cups_lang_t
*language
; /* Local language */
1057 int fd
; /* PPD file */
1058 char uri
[HTTP_MAX_URI
], /* Printer URI */
1059 printer
[HTTP_MAX_URI
], /* Printer name */
1060 method
[HTTP_MAX_URI
], /* Method/scheme name */
1061 username
[HTTP_MAX_URI
], /* Username:password */
1062 hostname
[HTTP_MAX_URI
], /* Hostname */
1063 resource
[HTTP_MAX_URI
]; /* Resource name */
1064 int port
; /* Port number */
1065 http_status_t status
; /* HTTP status from server */
1066 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1067 static const char * const requested_attrs
[] =
1068 { /* Requested attributes */
1069 "printer-uri-supported",
1076 * Range check input...
1079 DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http
,
1080 name
? name
: "(null)"));
1084 cg
->last_error
= IPP_INTERNAL_ERROR
;
1089 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1092 * attributes-charset
1093 * attributes-natural-language
1095 * requested-attributes
1100 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1101 request
->request
.op
.request_id
= 1;
1103 language
= cupsLangDefault();
1105 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1106 "attributes-charset", NULL
, cupsLangEncoding(language
));
1108 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1109 "attributes-natural-language", NULL
, language
->language
);
1111 cupsLangFree(language
);
1113 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", name
);
1114 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1115 "printer-uri", NULL
, uri
);
1117 DEBUG_printf(("cupsGetPPD2: printer-uri=\"%s\"\n", uri
));
1119 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1120 "requested-attributes",
1121 sizeof(requested_attrs
) / sizeof(requested_attrs
[0]),
1122 NULL
, requested_attrs
);
1125 * Do the request and get back a response...
1128 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1130 cg
->last_error
= response
->request
.status
.status_code
;
1134 if ((attr
= ippFindAttribute(response
, "member-uris", IPP_TAG_URI
)) != NULL
)
1137 * Get the first actual server and printer name in the class...
1140 for (i
= 0; i
< attr
->num_values
; i
++)
1142 httpSeparate(attr
->values
[0].string
.text
, method
, username
, hostname
,
1144 if (strncmp(resource
, "/printers/", 10) == 0)
1150 strlcpy(printer
, resource
+ 10, sizeof(printer
));
1155 else if ((attr
= ippFindAttribute(response
, "printer-uri-supported",
1156 IPP_TAG_URI
)) != NULL
)
1159 * Get the actual server and printer names...
1162 httpSeparate(attr
->values
[0].string
.text
, method
, username
, hostname
,
1164 strlcpy(printer
, strrchr(resource
, '/') + 1, sizeof(printer
));
1167 ippDelete(response
);
1170 * Remap local hostname to localhost...
1173 gethostname(uri
, sizeof(uri
));
1175 if (strcasecmp(uri
, hostname
) == 0)
1176 strcpy(hostname
, "localhost");
1181 cg
->last_error
= IPP_NOT_FOUND
;
1186 * Reconnect to the correct server as needed...
1189 if (!strcasecmp(http
->hostname
, hostname
))
1191 else if ((http2
= httpConnectEncrypt(hostname
, ippPort(),
1192 cupsEncryption())) == NULL
)
1194 DEBUG_puts("Unable to connect to server!");
1195 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1200 * Get a temp file...
1203 if ((fd
= cupsTempFd(cg
->ppd_filename
, sizeof(cg
->ppd_filename
))) < 0)
1206 * Can't open file; close the server connection and return NULL...
1209 cg
->last_error
= IPP_INTERNAL_ERROR
;
1218 * And send a request to the HTTP server...
1221 snprintf(resource
, sizeof(resource
), "/printers/%s.ppd", printer
);
1223 status
= cupsGetFd(http2
, resource
, fd
);
1231 * See if we actually got the file or an error...
1234 if (status
!= HTTP_OK
)
1238 case HTTP_NOT_FOUND
:
1239 cg
->last_error
= IPP_NOT_FOUND
;
1242 DEBUG_puts("Mapping HTTP error to IPP_ERROR");
1243 cg
->last_error
= IPP_ERROR
;
1245 case HTTP_UNAUTHORIZED
:
1246 cg
->last_error
= IPP_NOT_AUTHORIZED
;
1249 cg
->last_error
= IPP_INTERNAL_ERROR
;
1253 unlink(cg
->ppd_filename
);
1259 * Return the PPD file...
1262 return (cg
->ppd_filename
);
1267 * 'cupsGetPrinters()' - Get a list of printers.
1270 int /* O - Number of printers */
1271 cupsGetPrinters(char ***printers
) /* O - Printers */
1273 int n
; /* Number of printers */
1274 ipp_t
*request
, /* IPP Request */
1275 *response
; /* IPP Response */
1276 ipp_attribute_t
*attr
; /* Current attribute */
1277 cups_lang_t
*language
; /* Default language */
1278 char **temp
; /* Temporary pointer */
1279 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1282 if (printers
== NULL
)
1284 cg
->last_error
= IPP_INTERNAL_ERROR
;
1289 * Try to connect to the server...
1292 if (!cups_connect("default", NULL
, NULL
))
1294 DEBUG_puts("Unable to connect to server!");
1295 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1300 * Build a CUPS_GET_PRINTERS request, which requires the following
1303 * attributes-charset
1304 * attributes-natural-language
1305 * requested-attributes
1310 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
1311 request
->request
.op
.request_id
= 1;
1313 language
= cupsLangDefault();
1315 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1316 "attributes-charset", NULL
, cupsLangEncoding(language
));
1318 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1319 "attributes-natural-language", NULL
, language
->language
);
1321 cupsLangFree(language
);
1323 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1324 "requested-attributes", NULL
, "printer-name");
1327 * Do the request and get back a response...
1333 if ((response
= cupsDoRequest(cg
->http
, request
, "/")) != NULL
)
1335 cg
->last_error
= response
->request
.status
.status_code
;
1337 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1338 if (attr
->name
!= NULL
&&
1339 strcasecmp(attr
->name
, "printer-name") == 0 &&
1340 attr
->value_tag
== IPP_TAG_NAME
)
1343 temp
= malloc(sizeof(char *));
1345 temp
= realloc(*printers
, sizeof(char *) * (n
+ 1));
1350 * Ran out of memory!
1356 free((*printers
)[n
]);
1360 ippDelete(response
);
1365 temp
[n
] = strdup(attr
->values
[0].string
.text
);
1369 ippDelete(response
);
1372 cg
->last_error
= IPP_BAD_REQUEST
;
1379 * 'cupsLastError()' - Return the last IPP error that occurred.
1382 ipp_status_t
/* O - IPP error code */
1385 return (_cupsGlobals()->last_error
);
1390 * 'cupsPrintFile()' - Print a file to a printer or class.
1393 int /* O - Job ID */
1394 cupsPrintFile(const char *name
, /* I - Printer or class name */
1395 const char *filename
, /* I - File to print */
1396 const char *title
, /* I - Title of job */
1397 int num_options
,/* I - Number of options */
1398 cups_option_t
*options
) /* I - Options */
1400 DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
1401 "title=\"%s\", num_options=%d, options=%p)\n",
1402 name
, filename
, title
, num_options
, options
));
1404 return (cupsPrintFiles(name
, 1, &filename
, title
, num_options
, options
));
1409 * 'cupsPrintFile2()' - Print a file to a printer or class.
1412 int /* O - Job ID */
1413 cupsPrintFile2(http_t
*http
, /* I - HTTP connection */
1414 const char *name
, /* I - Printer or class name */
1415 const char *filename
, /* I - File to print */
1416 const char *title
, /* I - Title of job */
1418 /* I - Number of options */
1419 cups_option_t
*options
) /* I - Options */
1421 DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", "
1422 "title=\"%s\", num_options=%d, options=%p)\n",
1423 http
, name
, filename
, title
, num_options
, options
));
1425 return (cupsPrintFiles2(http
, name
, 1, &filename
, title
, num_options
, options
));
1430 * 'cupsPrintFiles()' - Print one or more files to a printer or class.
1433 int /* O - Job ID */
1434 cupsPrintFiles(const char *name
, /* I - Printer or class name */
1435 int num_files
, /* I - Number of files */
1436 const char **files
, /* I - File(s) to print */
1437 const char *title
, /* I - Title of job */
1439 /* I - Number of options */
1440 cups_option_t
*options
) /* I - Options */
1442 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1444 DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, "
1445 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1446 name
, num_files
, files
, title
, num_options
, options
));
1450 * Setup a connection and request data...
1453 if (!cups_connect(name
, NULL
, NULL
))
1455 DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n",
1457 DEBUG_puts("Unable to connect to server!");
1458 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1463 * Print the file(s)...
1466 return (cupsPrintFiles2(cg
->http
, name
, num_files
, files
, title
,
1467 num_options
, options
));
1473 * 'cupsPrintFiles2()' - Print one or more files to a printer or class.
1476 int /* O - Job ID */
1477 cupsPrintFiles2(http_t
*http
, /* I - HTTP connection */
1478 const char *name
, /* I - Printer or class name */
1479 int num_files
,/* I - Number of files */
1480 const char **files
, /* I - File(s) to print */
1481 const char *title
, /* I - Title of job */
1483 /* I - Number of options */
1484 cups_option_t
*options
) /* I - Options */
1486 int i
; /* Looping var */
1487 const char *val
; /* Pointer to option value */
1488 ipp_t
*request
; /* IPP request */
1489 ipp_t
*response
; /* IPP response */
1490 ipp_attribute_t
*attr
; /* IPP job-id attribute */
1491 char uri
[HTTP_MAX_URI
]; /* Printer URI */
1492 cups_lang_t
*language
; /* Language to use */
1493 int jobid
; /* New job ID */
1494 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1497 DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, "
1498 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1499 http
, name
, num_files
, files
, title
, num_options
, options
));
1502 * Range check input...
1505 if (!http
|| !name
|| num_files
< 1 || files
== NULL
)
1509 * Setup the request data...
1512 language
= cupsLangDefault();
1515 * Build a standard CUPS URI for the printer and fill the standard IPP
1519 if ((request
= ippNew()) == NULL
)
1522 request
->request
.op
.operation_id
= num_files
== 1 ? IPP_PRINT_JOB
:
1524 request
->request
.op
.request_id
= 1;
1526 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/printers/%s", http
->hostname
,
1529 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1530 "attributes-charset", NULL
, cupsLangEncoding(language
));
1532 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1533 "attributes-natural-language", NULL
,
1534 language
!= NULL
? language
->language
: "C");
1536 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1539 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1543 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
1547 * Then add all options...
1550 cupsEncodeOptions(request
, num_options
, options
);
1556 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1559 response
= cupsDoFileRequest(http
, request
, uri
, *files
);
1561 response
= cupsDoRequest(http
, request
, uri
);
1563 if (response
== NULL
)
1565 else if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1567 DEBUG_printf(("IPP response code was 0x%x!\n",
1568 response
->request
.status
.status_code
));
1571 else if ((attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
1573 DEBUG_puts("No job ID!");
1575 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;
1580 jobid
= attr
->values
[0].integer
;
1582 if (response
!= NULL
)
1583 ippDelete(response
);
1586 * Handle multiple file jobs if the create-job operation worked...
1589 if (jobid
> 0 && num_files
> 1)
1590 for (i
= 0; i
< num_files
; i
++)
1593 * Build a standard CUPS URI for the job and fill the standard IPP
1597 if ((request
= ippNew()) == NULL
)
1600 request
->request
.op
.operation_id
= IPP_SEND_DOCUMENT
;
1601 request
->request
.op
.request_id
= 1;
1603 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/jobs/%d", http
->hostname
,
1606 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1607 "attributes-charset", NULL
, cupsLangEncoding(language
));
1609 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1610 "attributes-natural-language", NULL
,
1611 language
!= NULL
? language
->language
: "C");
1613 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
1617 * Handle raw print files...
1620 if (cupsGetOption("raw", num_options
, options
))
1621 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
, "document-format",
1622 NULL
, "application/vnd.cups-raw");
1623 else if ((val
= cupsGetOption("document-format", num_options
, options
)) != NULL
)
1624 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
, "document-format",
1627 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
, "document-format",
1628 NULL
, "application/octet-stream");
1630 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1634 * Is this the last document?
1637 if (i
== (num_files
- 1))
1638 ippAddBoolean(request
, IPP_TAG_OPERATION
, "last-document", 1);
1644 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1646 if ((response
= cupsDoFileRequest(http
, request
, uri
,
1648 ippDelete(response
);
1651 cupsLangFree(language
);
1658 * 'cups_connect()' - Connect to the specified host...
1661 static char * /* I - Printer name or NULL */
1662 cups_connect(const char *name
, /* I - Destination (printer[@host]) */
1663 char *printer
, /* O - Printer name [HTTP_MAX_URI] */
1664 char *hostname
) /* O - Hostname [HTTP_MAX_URI] */
1666 char hostbuf
[HTTP_MAX_URI
]; /* Name of host */
1667 cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
1670 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name
, printer
, hostname
));
1674 cg
->last_error
= IPP_BAD_REQUEST
;
1679 * All jobs are now queued to cupsServer() to avoid hostname
1680 * resolution problems and to ensure that the user sees all
1681 * locally queued jobs locally.
1684 strlcpy(hostbuf
, cupsServer(), sizeof(hostbuf
));
1686 if (hostname
!= NULL
)
1687 strlcpy(hostname
, hostbuf
, HTTP_MAX_URI
);
1691 if (printer
!= NULL
)
1692 strlcpy(printer
, name
, HTTP_MAX_URI
);
1694 printer
= (char *)name
;
1696 if (cg
->http
!= NULL
)
1698 if (strcasecmp(cg
->http
->hostname
, hostname
) == 0)
1701 httpClose(cg
->http
);
1704 DEBUG_printf(("connecting to %s on port %d...\n", hostname
, ippPort()));
1706 if ((cg
->http
= httpConnectEncrypt(hostname
, ippPort(),
1707 cupsEncryption())) == NULL
)
1709 DEBUG_puts("Unable to connect to server!");
1710 cg
->last_error
= IPP_SERVICE_UNAVAILABLE
;