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...
60 #if defined(WIN32) || defined(__EMX__)
64 #endif /* WIN32 || __EMX__ */
71 static http_t
*cups_server
= NULL
; /* Current server connection */
72 static ipp_status_t last_error
= IPP_OK
; /* Last IPP error */
79 static char *cups_connect(const char *name
, char *printer
, char *hostname
);
83 * 'cupsCancelJob()' - Cancel a print job.
86 int /* O - 1 on success, 0 on failure */
87 cupsCancelJob(const char *name
, /* I - Name of printer or class */
88 int job
) /* I - Job ID */
90 char printer
[HTTP_MAX_URI
], /* Printer name */
91 hostname
[HTTP_MAX_URI
], /* Hostname */
92 uri
[HTTP_MAX_URI
]; /* Printer URI */
93 ipp_t
*request
, /* IPP request */
94 *response
; /* IPP response */
95 cups_lang_t
*language
; /* Language info */
99 * See if we can connect to the server...
102 if (!cups_connect(name
, printer
, hostname
))
104 DEBUG_puts("Unable to connect to server!");
105 last_error
= IPP_SERVICE_UNAVAILABLE
;
110 * Build an IPP_CANCEL_JOB request, which requires the following
114 * attributes-natural-language
117 * [requesting-user-name]
122 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
123 request
->request
.op
.request_id
= 1;
125 language
= cupsLangDefault();
127 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
128 "attributes-charset", NULL
, cupsLangEncoding(language
));
130 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
131 "attributes-natural-language", NULL
,
132 language
!= NULL
? language
->language
: "C");
134 cupsLangFree(language
);
136 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/printers/%s", hostname
, ippPort(), printer
);
137 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
140 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "job-id", job
);
142 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
149 if ((response
= cupsDoRequest(cups_server
, request
, "/jobs/")) != NULL
)
152 return (last_error
< IPP_REDIRECTION_OTHER_SITE
);
157 * 'cupsDoFileRequest()' - Do an IPP request...
160 ipp_t
* /* O - Response data */
161 cupsDoFileRequest(http_t
*http
, /* I - HTTP connection to server */
162 ipp_t
*request
, /* I - IPP request */
163 const char *resource
, /* I - HTTP resource for POST */
164 const char *filename
) /* I - File to send or NULL */
166 ipp_t
*response
; /* IPP response data */
167 char length
[255]; /* Content-Length field */
168 http_status_t status
; /* Status of HTTP request */
169 FILE *file
; /* File to send */
170 struct stat fileinfo
; /* File information */
171 int bytes
; /* Number of bytes read/written */
172 char buffer
[32768]; /* Output buffer */
175 DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
176 http
, request
, resource
? resource
: "(null)",
177 filename
? filename
: "(null)"));
179 if (http
== NULL
|| request
== NULL
|| resource
== NULL
)
184 last_error
= IPP_INTERNAL_ERROR
;
189 * See if we have a file to send...
192 if (filename
!= NULL
)
194 if (stat(filename
, &fileinfo
))
197 * Can't get file information!
201 last_error
= IPP_NOT_FOUND
;
206 if (fileinfo
.st_mode
& _S_IFDIR
)
208 if (S_ISDIR(fileinfo
.st_mode
))
212 * Can't send a directory...
216 last_error
= IPP_NOT_POSSIBLE
;
220 if ((file
= fopen(filename
, "rb")) == NULL
)
227 last_error
= IPP_NOT_FOUND
;
235 * Loop until we can send the request without authorization problems.
241 while (response
== NULL
)
243 DEBUG_puts("cupsDoFileRequest: setup...");
246 * Setup the HTTP variables needed...
249 if (filename
!= NULL
)
250 sprintf(length
, "%lu", (unsigned long)(ippLength(request
) +
251 (size_t)fileinfo
.st_size
));
253 sprintf(length
, "%lu", (unsigned long)ippLength(request
));
255 httpClearFields(http
);
256 httpSetField(http
, HTTP_FIELD_CONTENT_LENGTH
, length
);
257 httpSetField(http
, HTTP_FIELD_CONTENT_TYPE
, "application/ipp");
258 httpSetField(http
, HTTP_FIELD_AUTHORIZATION
, http
->authstring
);
260 DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http
->authstring
));
266 DEBUG_puts("cupsDoFileRequest: post...");
268 if (httpPost(http
, resource
))
270 if (httpReconnect(http
))
280 * Send the IPP data and wait for the response...
283 DEBUG_puts("cupsDoFileRequest: ipp write...");
285 request
->state
= IPP_IDLE
;
286 status
= HTTP_CONTINUE
;
288 if (ippWrite(http
, request
) != IPP_ERROR
)
289 if (filename
!= NULL
)
291 DEBUG_puts("cupsDoFileRequest: file write...");
299 while ((bytes
= fread(buffer
, 1, sizeof(buffer
), file
)) > 0)
303 if ((status
= httpUpdate(http
)) != HTTP_CONTINUE
)
307 if (httpWrite(http
, buffer
, bytes
) < bytes
)
313 * Get the server's return status...
316 DEBUG_puts("cupsDoFileRequest: update...");
318 while (status
== HTTP_CONTINUE
)
319 status
= httpUpdate(http
);
321 DEBUG_printf(("cupsDoFileRequest: status = %d\n", status
));
323 if (status
== HTTP_UNAUTHORIZED
)
325 DEBUG_puts("cupsDoFileRequest: unauthorized...");
328 * Flush any error message...
334 * See if we can do authentication...
337 if (cupsDoAuthentication(http
, "POST", resource
))
344 else if (status
== HTTP_ERROR
)
347 if (http
->error
!= WSAENETDOWN
&& http
->error
!= WSAENETUNREACH
)
349 if (http
->error
!= ENETDOWN
&& http
->error
!= ENETUNREACH
)
356 else if (status
== HTTP_UPGRADE_REQUIRED
)
358 /* Flush any error message... */
364 /* Upgrade with encryption... */
365 httpEncryption(http
, HTTP_ENCRYPT_REQUIRED
);
367 /* Try again, this time with encryption enabled... */
370 #endif /* HAVE_SSL */
371 else if (status
!= HTTP_OK
)
373 DEBUG_printf(("cupsDoFileRequest: error %d...\n", status
));
376 * Flush any error message...
385 * Read the response...
388 DEBUG_puts("cupsDoFileRequest: response...");
392 if (ippRead(http
, response
) == IPP_ERROR
)
395 * Delete the response...
398 DEBUG_puts("IPP read error!");
402 last_error
= IPP_SERVICE_UNAVAILABLE
;
409 * Close the file if needed...
412 if (filename
!= NULL
)
416 * Flush any remaining data...
422 * Delete the original request and return the response...
428 last_error
= response
->request
.status
.status_code
;
429 else if (status
!= HTTP_OK
)
433 case HTTP_NOT_FOUND
:
434 last_error
= IPP_NOT_FOUND
;
437 case HTTP_UNAUTHORIZED
:
438 last_error
= IPP_NOT_AUTHORIZED
;
441 case HTTP_FORBIDDEN
:
442 last_error
= IPP_FORBIDDEN
;
445 case HTTP_BAD_REQUEST
:
446 last_error
= IPP_BAD_REQUEST
;
449 case HTTP_REQUEST_TOO_LARGE
:
450 last_error
= IPP_REQUEST_VALUE
;
453 case HTTP_NOT_IMPLEMENTED
:
454 last_error
= IPP_OPERATION_NOT_SUPPORTED
;
457 case HTTP_NOT_SUPPORTED
:
458 last_error
= IPP_VERSION_NOT_SUPPORTED
;
462 DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
464 last_error
= IPP_SERVICE_UNAVAILABLE
;
474 * 'cupsFreeJobs()' - Free memory used by job data.
478 cupsFreeJobs(int num_jobs
, /* I - Number of jobs */
479 cups_job_t
*jobs
) /* I - Jobs */
481 int i
; /* Looping var */
484 if (num_jobs
<= 0 || jobs
== NULL
)
487 for (i
= 0; i
< num_jobs
; i
++)
491 free(jobs
[i
].format
);
500 * 'cupsGetClasses()' - Get a list of printer classes.
503 int /* O - Number of classes */
504 cupsGetClasses(char ***classes
) /* O - Classes */
506 int n
; /* Number of classes */
507 ipp_t
*request
, /* IPP Request */
508 *response
; /* IPP Response */
509 ipp_attribute_t
*attr
; /* Current attribute */
510 cups_lang_t
*language
; /* Default language */
511 char **temp
; /* Temporary pointer */
516 last_error
= IPP_INTERNAL_ERROR
;
521 * Try to connect to the server...
524 if (!cups_connect("default", NULL
, NULL
))
526 DEBUG_puts("Unable to connect to server!");
527 last_error
= IPP_SERVICE_UNAVAILABLE
;
532 * Build a CUPS_GET_CLASSES request, which requires the following
536 * attributes-natural-language
537 * requested-attributes
542 request
->request
.op
.operation_id
= CUPS_GET_CLASSES
;
543 request
->request
.op
.request_id
= 1;
545 language
= cupsLangDefault();
547 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
548 "attributes-charset", NULL
, cupsLangEncoding(language
));
550 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
551 "attributes-natural-language", NULL
, language
->language
);
553 cupsLangFree(language
);
555 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
556 "requested-attributes", NULL
, "printer-name");
559 * Do the request and get back a response...
565 if ((response
= cupsDoRequest(cups_server
, request
, "/")) != NULL
)
567 last_error
= response
->request
.status
.status_code
;
569 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
570 if (attr
->name
!= NULL
&&
571 strcasecmp(attr
->name
, "printer-name") == 0 &&
572 attr
->value_tag
== IPP_TAG_NAME
)
575 temp
= malloc(sizeof(char *));
577 temp
= realloc(*classes
, sizeof(char *) * (n
+ 1));
597 temp
[n
] = strdup(attr
->values
[0].string
.text
);
604 last_error
= IPP_BAD_REQUEST
;
611 * 'cupsGetDefault()' - Get the default printer or class.
614 const char * /* O - Default printer or NULL */
617 const char *var
; /* Environment variable */
621 * First see if the LPDEST or PRINTER environment variables are
622 * set... However, if PRINTER is set to "lp", ignore it to work
623 * around a "feature" in most Linux distributions - the default
624 * user login scripts set PRINTER to "lp"...
627 if ((var
= getenv("LPDEST")) != NULL
)
629 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
633 * Try to connect to the server...
636 if (!cups_connect("default", NULL
, NULL
))
638 DEBUG_puts("Unable to connect to server!");
639 last_error
= IPP_SERVICE_UNAVAILABLE
;
644 * Return the default printer...
647 return (cupsGetDefault2(cups_server
));
652 * 'cupsGetDefault2()' - Get the default printer or class.
655 const char * /* O - Default printer or NULL */
656 cupsGetDefault2(http_t
*http
) /* I - HTTP connection */
658 ipp_t
*request
, /* IPP Request */
659 *response
; /* IPP Response */
660 ipp_attribute_t
*attr
; /* Current attribute */
661 cups_lang_t
*language
; /* Default language */
662 const char *var
; /* Environment variable */
663 static char def_printer
[256]; /* Default printer */
667 * First see if the LPDEST or PRINTER environment variables are
668 * set... However, if PRINTER is set to "lp", ignore it to work
669 * around a "feature" in most Linux distributions - the default
670 * user login scripts set PRINTER to "lp"...
673 if ((var
= getenv("LPDEST")) != NULL
)
675 else if ((var
= getenv("PRINTER")) != NULL
&& strcmp(var
, "lp") != 0)
679 * Range check input...
686 * Build a CUPS_GET_DEFAULT request, which requires the following
690 * attributes-natural-language
695 request
->request
.op
.operation_id
= CUPS_GET_DEFAULT
;
696 request
->request
.op
.request_id
= 1;
698 language
= cupsLangDefault();
700 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
701 "attributes-charset", NULL
, cupsLangEncoding(language
));
703 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
704 "attributes-natural-language", NULL
, language
->language
);
706 cupsLangFree(language
);
709 * Do the request and get back a response...
712 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
714 last_error
= response
->request
.status
.status_code
;
716 if ((attr
= ippFindAttribute(response
, "printer-name", IPP_TAG_NAME
)) != NULL
)
718 strlcpy(def_printer
, attr
->values
[0].string
.text
, sizeof(def_printer
));
720 return (def_printer
);
726 last_error
= IPP_BAD_REQUEST
;
733 * 'cupsGetJobs()' - Get the jobs from the server.
736 int /* O - Number of jobs */
737 cupsGetJobs(cups_job_t
**jobs
, /* O - Job data */
738 const char *mydest
, /* I - Only show jobs for dest? */
739 int myjobs
, /* I - Only show my jobs? */
740 int completed
) /* I - Only show completed jobs? */
743 * Try to connect to the server...
746 if (!cups_connect("default", NULL
, NULL
))
748 DEBUG_puts("Unable to connect to server!");
749 last_error
= IPP_SERVICE_UNAVAILABLE
;
757 return (cupsGetJobs2(cups_server
, jobs
, mydest
, myjobs
, completed
));
763 * 'cupsGetJobs2()' - Get the jobs from the server.
766 int /* O - Number of jobs */
767 cupsGetJobs2(http_t
*http
, /* I - HTTP connection */
768 cups_job_t
**jobs
, /* O - Job data */
769 const char *mydest
, /* I - Only show jobs for dest? */
770 int myjobs
, /* I - Only show my jobs? */
771 int completed
) /* I - Only show completed jobs? */
773 int n
; /* Number of jobs */
774 ipp_t
*request
, /* IPP Request */
775 *response
; /* IPP Response */
776 ipp_attribute_t
*attr
; /* Current attribute */
777 cups_lang_t
*language
; /* Default language */
778 cups_job_t
*temp
; /* Temporary pointer */
780 priority
, /* job-priority */
781 size
; /* job-k-octets */
782 ipp_jstate_t state
; /* job-state */
783 time_t completed_time
, /* time-at-completed */
784 creation_time
, /* time-at-creation */
785 processing_time
; /* time-at-processing */
786 const char *dest
, /* job-printer-uri */
787 *format
, /* document-format */
788 *title
, /* job-name */
789 *user
; /* job-originating-user-name */
790 char uri
[HTTP_MAX_URI
]; /* URI for jobs */
791 static const char * const attrs
[] = /* Requested attributes */
799 "time-at-processing",
803 "job-originating-user-name"
809 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 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 last_error
= IPP_BAD_REQUEST
;
1008 if (n
== 0 && 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 */
1023 * See if we can connect to the server...
1026 if (!cups_connect(name
, NULL
, NULL
))
1028 DEBUG_puts("Unable to connect to server!");
1029 last_error
= IPP_SERVICE_UNAVAILABLE
;
1034 * Return the PPD file...
1037 return (cupsGetPPD2(cups_server
, name
));
1042 * 'cupsGetPPD2()' - Get the PPD file for a printer.
1045 const char * /* O - Filename for PPD file */
1046 cupsGetPPD2(http_t
*http
, /* I - HTTP connection */
1047 const char *name
) /* I - Printer name */
1049 int i
; /* Looping var */
1050 http_t
*http2
; /* Alternate HTTP connection */
1051 ipp_t
*request
, /* IPP request */
1052 *response
; /* IPP response */
1053 ipp_attribute_t
*attr
; /* Current attribute */
1054 cups_lang_t
*language
; /* Local language */
1055 int fd
; /* PPD file */
1056 char uri
[HTTP_MAX_URI
], /* Printer URI */
1057 printer
[HTTP_MAX_URI
], /* Printer name */
1058 method
[HTTP_MAX_URI
], /* Method/scheme name */
1059 username
[HTTP_MAX_URI
], /* Username:password */
1060 hostname
[HTTP_MAX_URI
], /* Hostname */
1061 resource
[HTTP_MAX_URI
]; /* Resource name */
1062 int port
; /* Port number */
1063 http_status_t status
; /* HTTP status from server */
1064 static char filename
[HTTP_MAX_URI
]; /* Local filename */
1065 static const char * const requested_attrs
[] =
1066 { /* Requested attributes */
1067 "printer-uri-supported",
1074 * Range check input...
1077 DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http
,
1078 name
? name
: "(null)"));
1082 last_error
= IPP_INTERNAL_ERROR
;
1087 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
1090 * attributes-charset
1091 * attributes-natural-language
1093 * requested-attributes
1098 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1099 request
->request
.op
.request_id
= 1;
1101 language
= cupsLangDefault();
1103 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1104 "attributes-charset", NULL
, cupsLangEncoding(language
));
1106 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1107 "attributes-natural-language", NULL
, language
->language
);
1109 cupsLangFree(language
);
1111 snprintf(uri
, sizeof(uri
), "ipp://localhost/printers/%s", name
);
1112 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1113 "printer-uri", NULL
, uri
);
1115 DEBUG_printf(("cupsGetPPD2: printer-uri=\"%s\"\n", uri
));
1117 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1118 "requested-attributes",
1119 sizeof(requested_attrs
) / sizeof(requested_attrs
[0]),
1120 NULL
, requested_attrs
);
1123 * Do the request and get back a response...
1126 if ((response
= cupsDoRequest(http
, request
, "/")) != NULL
)
1128 last_error
= response
->request
.status
.status_code
;
1132 if ((attr
= ippFindAttribute(response
, "member-uris", IPP_TAG_URI
)) != NULL
)
1135 * Get the first actual server and printer name in the class...
1138 for (i
= 0; i
< attr
->num_values
; i
++)
1140 httpSeparate(attr
->values
[0].string
.text
, method
, username
, hostname
,
1142 if (strncmp(resource
, "/printers/", 10) == 0)
1148 strlcpy(printer
, resource
+ 10, sizeof(printer
));
1153 else if ((attr
= ippFindAttribute(response
, "printer-uri-supported",
1154 IPP_TAG_URI
)) != NULL
)
1157 * Get the actual server and printer names...
1160 httpSeparate(attr
->values
[0].string
.text
, method
, username
, hostname
,
1162 strlcpy(printer
, strrchr(resource
, '/') + 1, sizeof(printer
));
1165 ippDelete(response
);
1168 * Remap local hostname to localhost...
1171 gethostname(uri
, sizeof(uri
));
1173 if (strcasecmp(uri
, hostname
) == 0)
1174 strcpy(hostname
, "localhost");
1179 last_error
= IPP_NOT_FOUND
;
1184 * Reconnect to the correct server as needed...
1187 if (!strcasecmp(http
->hostname
, hostname
))
1189 else if ((http2
= httpConnectEncrypt(hostname
, ippPort(),
1190 cupsEncryption())) == NULL
)
1192 DEBUG_puts("Unable to connect to server!");
1193 last_error
= IPP_SERVICE_UNAVAILABLE
;
1198 * Get a temp file...
1201 if ((fd
= cupsTempFd(filename
, sizeof(filename
))) < 0)
1204 * Can't open file; close the server connection and return NULL...
1207 last_error
= IPP_INTERNAL_ERROR
;
1216 * And send a request to the HTTP server...
1219 snprintf(resource
, sizeof(resource
), "/printers/%s.ppd", printer
);
1221 status
= cupsGetFd(http2
, resource
, fd
);
1229 * See if we actually got the file or an error...
1232 if (status
!= HTTP_OK
)
1236 case HTTP_NOT_FOUND
:
1237 last_error
= IPP_NOT_FOUND
;
1240 DEBUG_puts("Mapping HTTP error to IPP_ERROR");
1241 last_error
= IPP_ERROR
;
1243 case HTTP_UNAUTHORIZED
:
1244 last_error
= IPP_NOT_AUTHORIZED
;
1247 last_error
= IPP_INTERNAL_ERROR
;
1257 * Return the PPD file...
1265 * 'cupsGetPrinters()' - Get a list of printers.
1268 int /* O - Number of printers */
1269 cupsGetPrinters(char ***printers
) /* O - Printers */
1271 int n
; /* Number of printers */
1272 ipp_t
*request
, /* IPP Request */
1273 *response
; /* IPP Response */
1274 ipp_attribute_t
*attr
; /* Current attribute */
1275 cups_lang_t
*language
; /* Default language */
1276 char **temp
; /* Temporary pointer */
1279 if (printers
== NULL
)
1281 last_error
= IPP_INTERNAL_ERROR
;
1286 * Try to connect to the server...
1289 if (!cups_connect("default", NULL
, NULL
))
1291 DEBUG_puts("Unable to connect to server!");
1292 last_error
= IPP_SERVICE_UNAVAILABLE
;
1297 * Build a CUPS_GET_PRINTERS request, which requires the following
1300 * attributes-charset
1301 * attributes-natural-language
1302 * requested-attributes
1307 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
1308 request
->request
.op
.request_id
= 1;
1310 language
= cupsLangDefault();
1312 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1313 "attributes-charset", NULL
, cupsLangEncoding(language
));
1315 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1316 "attributes-natural-language", NULL
, language
->language
);
1318 cupsLangFree(language
);
1320 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_KEYWORD
,
1321 "requested-attributes", NULL
, "printer-name");
1324 * Do the request and get back a response...
1330 if ((response
= cupsDoRequest(cups_server
, request
, "/")) != NULL
)
1332 last_error
= response
->request
.status
.status_code
;
1334 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
)
1335 if (attr
->name
!= NULL
&&
1336 strcasecmp(attr
->name
, "printer-name") == 0 &&
1337 attr
->value_tag
== IPP_TAG_NAME
)
1340 temp
= malloc(sizeof(char *));
1342 temp
= realloc(*printers
, sizeof(char *) * (n
+ 1));
1347 * Ran out of memory!
1353 free((*printers
)[n
]);
1357 ippDelete(response
);
1362 temp
[n
] = strdup(attr
->values
[0].string
.text
);
1366 ippDelete(response
);
1369 last_error
= IPP_BAD_REQUEST
;
1376 * 'cupsLastError()' - Return the last IPP error that occurred.
1379 ipp_status_t
/* O - IPP error code */
1382 return (last_error
);
1386 * 'cupsPrintFile()' - Print a file to a printer or class.
1389 int /* O - Job ID */
1390 cupsPrintFile(const char *name
, /* I - Printer or class name */
1391 const char *filename
, /* I - File to print */
1392 const char *title
, /* I - Title of job */
1393 int num_options
,/* I - Number of options */
1394 cups_option_t
*options
) /* I - Options */
1396 DEBUG_printf(("cupsPrintFile(name=\"%s\", filename=\"%s\", "
1397 "title=\"%s\", num_options=%d, options=%p)\n",
1398 name
, filename
, title
, num_options
, options
));
1400 return (cupsPrintFiles(name
, 1, &filename
, title
, num_options
, options
));
1405 * 'cupsPrintFile2()' - Print a file to a printer or class.
1408 int /* O - Job ID */
1409 cupsPrintFile2(http_t
*http
, /* I - HTTP connection */
1410 const char *name
, /* I - Printer or class name */
1411 const char *filename
, /* I - File to print */
1412 const char *title
, /* I - Title of job */
1414 /* I - Number of options */
1415 cups_option_t
*options
) /* I - Options */
1417 DEBUG_printf(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", "
1418 "title=\"%s\", num_options=%d, options=%p)\n",
1419 http
, name
, filename
, title
, num_options
, options
));
1421 return (cupsPrintFiles2(http
, name
, 1, &filename
, title
, num_options
, options
));
1426 * 'cupsPrintFiles()' - Print one or more files to a printer or class.
1429 int /* O - Job ID */
1430 cupsPrintFiles(const char *name
, /* I - Printer or class name */
1431 int num_files
, /* I - Number of files */
1432 const char **files
, /* I - File(s) to print */
1433 const char *title
, /* I - Title of job */
1435 /* I - Number of options */
1436 cups_option_t
*options
) /* I - Options */
1438 DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, "
1439 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1440 name
, num_files
, files
, title
, num_options
, options
));
1444 * Setup a connection and request data...
1447 if (!cups_connect(name
, NULL
, NULL
))
1449 DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n",
1451 DEBUG_puts("Unable to connect to server!");
1452 last_error
= IPP_SERVICE_UNAVAILABLE
;
1457 * Print the file(s)...
1460 return (cupsPrintFiles2(cups_server
, name
, num_files
, files
, title
,
1461 num_options
, options
));
1467 * 'cupsPrintFiles2()' - Print one or more files to a printer or class.
1470 int /* O - Job ID */
1471 cupsPrintFiles2(http_t
*http
, /* I - HTTP connection */
1472 const char *name
, /* I - Printer or class name */
1473 int num_files
,/* I - Number of files */
1474 const char **files
, /* I - File(s) to print */
1475 const char *title
, /* I - Title of job */
1477 /* I - Number of options */
1478 cups_option_t
*options
) /* I - Options */
1480 int i
; /* Looping var */
1481 const char *val
; /* Pointer to option value */
1482 ipp_t
*request
; /* IPP request */
1483 ipp_t
*response
; /* IPP response */
1484 ipp_attribute_t
*attr
; /* IPP job-id attribute */
1485 char uri
[HTTP_MAX_URI
]; /* Printer URI */
1486 cups_lang_t
*language
; /* Language to use */
1487 int jobid
; /* New job ID */
1490 DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, "
1491 "files=%p, title=\"%s\", num_options=%d, options=%p)\n",
1492 http
, name
, num_files
, files
, title
, num_options
, options
));
1495 * Range check input...
1498 if (!http
|| !name
|| num_files
< 1 || files
== NULL
)
1502 * Setup the request data...
1505 language
= cupsLangDefault();
1508 * Build a standard CUPS URI for the printer and fill the standard IPP
1512 if ((request
= ippNew()) == NULL
)
1515 request
->request
.op
.operation_id
= num_files
== 1 ? IPP_PRINT_JOB
:
1517 request
->request
.op
.request_id
= 1;
1519 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/printers/%s", http
->hostname
,
1522 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1523 "attributes-charset", NULL
, cupsLangEncoding(language
));
1525 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1526 "attributes-natural-language", NULL
,
1527 language
!= NULL
? language
->language
: "C");
1529 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri",
1532 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1536 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
1540 * Then add all options...
1543 cupsEncodeOptions(request
, num_options
, options
);
1549 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1552 response
= cupsDoFileRequest(http
, request
, uri
, *files
);
1554 response
= cupsDoRequest(http
, request
, uri
);
1556 if (response
== NULL
)
1558 else if (response
->request
.status
.status_code
> IPP_OK_CONFLICT
)
1560 DEBUG_printf(("IPP response code was 0x%x!\n",
1561 response
->request
.status
.status_code
));
1564 else if ((attr
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
)) == NULL
)
1566 DEBUG_puts("No job ID!");
1568 last_error
= IPP_SERVICE_UNAVAILABLE
;
1573 jobid
= attr
->values
[0].integer
;
1575 if (response
!= NULL
)
1576 ippDelete(response
);
1579 * Handle multiple file jobs if the create-job operation worked...
1582 if (jobid
> 0 && num_files
> 1)
1583 for (i
= 0; i
< num_files
; i
++)
1586 * Build a standard CUPS URI for the job and fill the standard IPP
1590 if ((request
= ippNew()) == NULL
)
1593 request
->request
.op
.operation_id
= IPP_SEND_DOCUMENT
;
1594 request
->request
.op
.request_id
= 1;
1596 snprintf(uri
, sizeof(uri
), "ipp://%s:%d/jobs/%d", http
->hostname
,
1599 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1600 "attributes-charset", NULL
, cupsLangEncoding(language
));
1602 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1603 "attributes-natural-language", NULL
,
1604 language
!= NULL
? language
->language
: "C");
1606 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri",
1610 * Handle raw print files...
1613 if (cupsGetOption("raw", num_options
, options
))
1614 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
, "document-format",
1615 NULL
, "application/vnd.cups-raw");
1616 else if ((val
= cupsGetOption("document-format", num_options
, options
)) != NULL
)
1617 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
, "document-format",
1620 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_MIMETYPE
, "document-format",
1621 NULL
, "application/octet-stream");
1623 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1627 * Is this the last document?
1630 if (i
== (num_files
- 1))
1631 ippAddBoolean(request
, IPP_TAG_OPERATION
, "last-document", 1);
1637 snprintf(uri
, sizeof(uri
), "/printers/%s", name
);
1639 if ((response
= cupsDoFileRequest(http
, request
, uri
,
1641 ippDelete(response
);
1644 cupsLangFree(language
);
1651 * 'cups_connect()' - Connect to the specified host...
1654 static char * /* I - Printer name or NULL */
1655 cups_connect(const char *name
, /* I - Destination (printer[@host]) */
1656 char *printer
, /* O - Printer name [HTTP_MAX_URI] */
1657 char *hostname
) /* O - Hostname [HTTP_MAX_URI] */
1659 char hostbuf
[HTTP_MAX_URI
]; /* Name of host */
1662 DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name
, printer
, hostname
));
1666 last_error
= IPP_BAD_REQUEST
;
1671 * All jobs are now queued to cupsServer() to avoid hostname
1672 * resolution problems and to ensure that the user sees all
1673 * locally queued jobs locally.
1676 strlcpy(hostbuf
, cupsServer(), sizeof(hostbuf
));
1678 if (hostname
!= NULL
)
1679 strlcpy(hostname
, hostbuf
, HTTP_MAX_URI
);
1683 if (printer
!= NULL
)
1684 strlcpy(printer
, name
, HTTP_MAX_URI
);
1686 printer
= (char *)name
;
1688 if (cups_server
!= NULL
)
1690 if (strcasecmp(cups_server
->hostname
, hostname
) == 0)
1693 httpClose(cups_server
);
1696 DEBUG_printf(("connecting to %s on port %d...\n", hostname
, ippPort()));
1698 if ((cups_server
= httpConnectEncrypt(hostname
, ippPort(),
1699 cupsEncryption())) == NULL
)
1701 DEBUG_puts("Unable to connect to server!");
1702 last_error
= IPP_SERVICE_UNAVAILABLE
;