2 * Support code for the Common UNIX Printing System ("CUPS")
4 * Copyright 1999-2003 by Michael R Sweet.
5 * Copyright 2008 Jeremy Allison.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 * JRA. Converted to utf8 pull/push.
27 #include "printing/pcap.h"
28 #include "librpc/gen_ndr/ndr_printcap.h"
31 #include <cups/cups.h>
32 #include <cups/language.h>
34 static SIG_ATOMIC_T gotalarm
;
36 /***************************************************************
37 Signal function to tell us we timed out.
38 ****************************************************************/
40 static void gotalarm_sig(int signum
)
45 extern userdom_struct current_user_info
;
48 * 'cups_passwd_cb()' - The CUPS password callback...
51 static const char * /* O - Password or NULL */
52 cups_passwd_cb(const char *prompt
) /* I - Prompt */
55 * Always return NULL to indicate that no password is available...
61 static http_t
*cups_connect(TALLOC_CTX
*frame
)
64 char *server
= NULL
, *p
= NULL
;
66 int timeout
= lp_cups_connection_timeout();
69 if (lp_cups_server() != NULL
&& strlen(lp_cups_server()) > 0) {
70 if (!push_utf8_talloc(frame
, &server
, lp_cups_server(), &size
)) {
74 server
= talloc_strdup(frame
,cupsServer());
80 p
= strchr(server
, ':');
88 DEBUG(10, ("connecting to cups server %s:%d\n",
94 CatchSignal(SIGALRM
, gotalarm_sig
);
98 #ifdef HAVE_HTTPCONNECTENCRYPT
99 http
= httpConnectEncrypt(server
, port
, lp_cups_encrypt());
101 http
= httpConnect(server
, port
);
105 CatchSignal(SIGALRM
, SIG_IGN
);
109 DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n",
110 server
, port
, strerror(errno
)));
116 static bool send_pcap_blob(DATA_BLOB
*pcap_blob
, int fd
)
120 ret
= sys_write(fd
, &pcap_blob
->length
, sizeof(pcap_blob
->length
));
121 if (ret
!= sizeof(pcap_blob
->length
)) {
125 ret
= sys_write(fd
, pcap_blob
->data
, pcap_blob
->length
);
126 if (ret
!= pcap_blob
->length
) {
130 DEBUG(10, ("successfully sent blob of len %d\n", (int)ret
));
134 static bool recv_pcap_blob(TALLOC_CTX
*mem_ctx
, int fd
, DATA_BLOB
*pcap_blob
)
139 ret
= sys_read(fd
, &blob_len
, sizeof(blob_len
));
140 if (ret
!= sizeof(blob_len
)) {
144 *pcap_blob
= data_blob_talloc_named(mem_ctx
, NULL
, blob_len
,
146 if (pcap_blob
->length
!= blob_len
) {
149 ret
= sys_read(fd
, pcap_blob
->data
, blob_len
);
150 if (ret
!= blob_len
) {
151 talloc_free(pcap_blob
->data
);
155 DEBUG(10, ("successfully recvd blob of len %d\n", (int)ret
));
159 static bool process_cups_printers_response(TALLOC_CTX
*mem_ctx
,
161 struct pcap_data
*pcap_data
)
163 ipp_attribute_t
*attr
;
166 char *location
= NULL
;
167 struct pcap_printer
*printer
;
170 for (attr
= response
->attrs
; attr
!= NULL
;) {
172 * Skip leading attributes until we hit a printer...
175 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
182 * Pull the needed attributes from this printer...
188 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
) {
190 if (strcmp(attr
->name
, "printer-name") == 0 &&
191 attr
->value_tag
== IPP_TAG_NAME
) {
192 if (!pull_utf8_talloc(mem_ctx
,
194 attr
->values
[0].string
.text
,
200 if (strcmp(attr
->name
, "printer-info") == 0 &&
201 attr
->value_tag
== IPP_TAG_TEXT
) {
202 if (!pull_utf8_talloc(mem_ctx
,
204 attr
->values
[0].string
.text
,
210 if (strcmp(attr
->name
, "printer-location") == 0 &&
211 attr
->value_tag
== IPP_TAG_TEXT
) {
212 if (!pull_utf8_talloc(mem_ctx
,
214 attr
->values
[0].string
.text
,
224 * See if we have everything needed...
230 if (pcap_data
->count
== 0) {
231 printer
= talloc_array(mem_ctx
, struct pcap_printer
, 1);
233 printer
= talloc_realloc(mem_ctx
, pcap_data
->printers
,
235 pcap_data
->count
+ 1);
237 if (printer
== NULL
) {
240 pcap_data
->printers
= printer
;
241 pcap_data
->printers
[pcap_data
->count
].name
= name
;
242 pcap_data
->printers
[pcap_data
->count
].info
= info
;
243 pcap_data
->printers
[pcap_data
->count
].location
= location
;
253 * request printer list from cups, send result back to up parent via fd.
254 * returns true if the (possibly failed) result was successfuly sent to parent.
256 static bool cups_cache_reload_async(int fd
)
258 TALLOC_CTX
*frame
= talloc_stackframe();
259 struct pcap_data pcap_data
;
260 http_t
*http
= NULL
; /* HTTP connection to server */
261 ipp_t
*request
= NULL
, /* IPP Request */
262 *response
= NULL
; /* IPP Response */
263 cups_lang_t
*language
= NULL
; /* Default language */
264 static const char *requested
[] =/* Requested attributes */
271 enum ndr_err_code ndr_ret
;
274 ZERO_STRUCT(pcap_data
);
275 pcap_data
.status
= NT_STATUS_UNSUCCESSFUL
;
277 DEBUG(5, ("reloading cups printcap cache\n"));
280 * Make sure we don't ask for passwords...
283 cupsSetPasswordCB(cups_passwd_cb
);
285 if ((http
= cups_connect(frame
)) == NULL
) {
290 * Build a CUPS_GET_PRINTERS request, which requires the following
294 * attributes-natural-language
295 * requested-attributes
300 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
301 request
->request
.op
.request_id
= 1;
303 language
= cupsLangDefault();
305 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
306 "attributes-charset", NULL
, "utf-8");
308 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
309 "attributes-natural-language", NULL
, language
->language
);
311 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
312 "requested-attributes",
313 (sizeof(requested
) / sizeof(requested
[0])),
316 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
317 DEBUG(0,("Unable to get printer list - %s\n",
318 ippErrorString(cupsLastError())));
322 ret
= process_cups_printers_response(frame
, response
, &pcap_data
);
324 DEBUG(0,("failed to process cups response\n"));
332 * Build a CUPS_GET_CLASSES request, which requires the following
336 * attributes-natural-language
337 * requested-attributes
342 request
->request
.op
.operation_id
= CUPS_GET_CLASSES
;
343 request
->request
.op
.request_id
= 1;
345 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
346 "attributes-charset", NULL
, "utf-8");
348 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
349 "attributes-natural-language", NULL
, language
->language
);
351 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
352 "requested-attributes",
353 (sizeof(requested
) / sizeof(requested
[0])),
356 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
357 DEBUG(0,("Unable to get printer list - %s\n",
358 ippErrorString(cupsLastError())));
362 ret
= process_cups_printers_response(frame
, response
, &pcap_data
);
364 DEBUG(0,("failed to process cups response\n"));
368 pcap_data
.status
= NT_STATUS_OK
;
374 cupsLangFree(language
);
380 ndr_ret
= ndr_push_struct_blob(&pcap_blob
, frame
, &pcap_data
,
381 (ndr_push_flags_fn_t
)ndr_push_pcap_data
);
382 if (ndr_ret
== NDR_ERR_SUCCESS
) {
383 ret
= send_pcap_blob(&pcap_blob
, fd
);
390 static struct fd_event
*cache_fd_event
;
392 static bool cups_pcap_load_async(struct tevent_context
*ev
,
393 struct messaging_context
*msg_ctx
,
402 if (cache_fd_event
) {
403 DEBUG(3,("cups_pcap_load_async: already waiting for "
404 "a refresh event\n" ));
408 DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n"));
410 if (pipe(fds
) == -1) {
415 if (pid
== (pid_t
)-1) {
416 DEBUG(10,("cups_pcap_load_async: fork failed %s\n",
424 DEBUG(10,("cups_pcap_load_async: child pid = %u\n",
425 (unsigned int)pid
));
434 close_all_print_db();
436 status
= reinit_after_fork(msg_ctx
, ev
, true);
437 if (!NT_STATUS_IS_OK(status
)) {
438 DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
439 smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
443 cups_cache_reload_async(fds
[1]);
448 struct cups_async_cb_args
{
450 struct event_context
*event_ctx
;
451 struct messaging_context
*msg_ctx
;
452 void (*post_cache_fill_fn
)(struct event_context
*,
453 struct messaging_context
*);
456 static void cups_async_callback(struct event_context
*event_ctx
,
457 struct fd_event
*event
,
461 TALLOC_CTX
*frame
= talloc_stackframe();
462 struct cups_async_cb_args
*cb_args
= (struct cups_async_cb_args
*)p
;
463 struct pcap_cache
*tmp_pcap_cache
= NULL
;
465 struct pcap_data pcap_data
;
467 enum ndr_err_code ndr_ret
;
470 DEBUG(5,("cups_async_callback: callback received for printer data. "
471 "fd = %d\n", cb_args
->pipe_fd
));
473 ret_ok
= recv_pcap_blob(frame
, cb_args
->pipe_fd
, &pcap_blob
);
475 DEBUG(0,("failed to recv pcap blob\n"));
479 ndr_ret
= ndr_pull_struct_blob(&pcap_blob
, frame
, &pcap_data
,
480 (ndr_pull_flags_fn_t
)ndr_pull_pcap_data
);
481 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
485 if (!NT_STATUS_IS_OK(pcap_data
.status
)) {
486 DEBUG(0,("failed to retrieve printer list: %s\n",
487 nt_errstr(pcap_data
.status
)));
491 for (i
= 0; i
< pcap_data
.count
; i
++) {
492 ret_ok
= pcap_cache_add_specific(&tmp_pcap_cache
,
493 pcap_data
.printers
[i
].name
,
494 pcap_data
.printers
[i
].info
,
495 pcap_data
.printers
[i
].location
);
497 DEBUG(0, ("failed to add to tmp pcap cache\n"));
502 /* replace the system-wide pcap cache with a (possibly empty) new one */
503 ret_ok
= pcap_cache_replace(tmp_pcap_cache
);
505 DEBUG(0, ("failed to replace pcap cache\n"));
506 } else if (cb_args
->post_cache_fill_fn
!= NULL
) {
507 /* Caller requested post cache fill callback */
508 cb_args
->post_cache_fill_fn(cb_args
->event_ctx
,
512 pcap_cache_destroy_specific(&tmp_pcap_cache
);
514 close(cb_args
->pipe_fd
);
515 TALLOC_FREE(cb_args
);
516 TALLOC_FREE(cache_fd_event
);
519 bool cups_cache_reload(struct tevent_context
*ev
,
520 struct messaging_context
*msg_ctx
,
521 void (*post_cache_fill_fn
)(struct tevent_context
*,
522 struct messaging_context
*))
524 struct cups_async_cb_args
*cb_args
;
527 cb_args
= talloc(NULL
, struct cups_async_cb_args
);
528 if (cb_args
== NULL
) {
532 cb_args
->post_cache_fill_fn
= post_cache_fill_fn
;
533 cb_args
->event_ctx
= ev
;
534 cb_args
->msg_ctx
= msg_ctx
;
535 p_pipe_fd
= &cb_args
->pipe_fd
;
538 /* Set up an async refresh. */
539 if (!cups_pcap_load_async(ev
, msg_ctx
, p_pipe_fd
)) {
540 talloc_free(cb_args
);
544 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
547 /* Trigger an event when the pipe can be read. */
548 cache_fd_event
= event_add_fd(ev
,
553 if (!cache_fd_event
) {
555 TALLOC_FREE(cb_args
);
563 * 'cups_job_delete()' - Delete a job.
566 static int cups_job_delete(const char *sharename
, const char *lprm_command
, struct printjob
*pjob
)
568 TALLOC_CTX
*frame
= talloc_stackframe();
569 int ret
= 1; /* Return value */
570 http_t
*http
= NULL
; /* HTTP connection to server */
571 ipp_t
*request
= NULL
, /* IPP Request */
572 *response
= NULL
; /* IPP Response */
573 cups_lang_t
*language
= NULL
; /* Default language */
575 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
578 DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename
, pjob
, pjob
->sysjob
));
581 * Make sure we don't ask for passwords...
584 cupsSetPasswordCB(cups_passwd_cb
);
587 * Try to connect to the server...
590 if ((http
= cups_connect(frame
)) == NULL
) {
595 * Build an IPP_CANCEL_JOB request, which requires the following
599 * attributes-natural-language
601 * requesting-user-name
606 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
607 request
->request
.op
.request_id
= 1;
609 language
= cupsLangDefault();
611 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
612 "attributes-charset", NULL
, "utf-8");
614 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
615 "attributes-natural-language", NULL
, language
->language
);
617 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/jobs/%d", pjob
->sysjob
);
619 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
621 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
625 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
629 * Do the request and get back a response...
632 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
) {
633 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
634 DEBUG(0,("Unable to cancel job %d - %s\n", pjob
->sysjob
,
635 ippErrorString(cupsLastError())));
640 DEBUG(0,("Unable to cancel job %d - %s\n", pjob
->sysjob
,
641 ippErrorString(cupsLastError())));
649 cupsLangFree(language
);
660 * 'cups_job_pause()' - Pause a job.
663 static int cups_job_pause(int snum
, struct printjob
*pjob
)
665 TALLOC_CTX
*frame
= talloc_stackframe();
666 int ret
= 1; /* Return value */
667 http_t
*http
= NULL
; /* HTTP connection to server */
668 ipp_t
*request
= NULL
, /* IPP Request */
669 *response
= NULL
; /* IPP Response */
670 cups_lang_t
*language
= NULL
; /* Default language */
672 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
675 DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum
, pjob
, pjob
->sysjob
));
678 * Make sure we don't ask for passwords...
681 cupsSetPasswordCB(cups_passwd_cb
);
684 * Try to connect to the server...
687 if ((http
= cups_connect(frame
)) == NULL
) {
692 * Build an IPP_HOLD_JOB request, which requires the following
696 * attributes-natural-language
698 * requesting-user-name
703 request
->request
.op
.operation_id
= IPP_HOLD_JOB
;
704 request
->request
.op
.request_id
= 1;
706 language
= cupsLangDefault();
708 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
709 "attributes-charset", NULL
, "utf-8");
711 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
712 "attributes-natural-language", NULL
, language
->language
);
714 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/jobs/%d", pjob
->sysjob
);
716 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
718 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
721 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
725 * Do the request and get back a response...
728 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
) {
729 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
730 DEBUG(0,("Unable to hold job %d - %s\n", pjob
->sysjob
,
731 ippErrorString(cupsLastError())));
736 DEBUG(0,("Unable to hold job %d - %s\n", pjob
->sysjob
,
737 ippErrorString(cupsLastError())));
745 cupsLangFree(language
);
756 * 'cups_job_resume()' - Resume a paused job.
759 static int cups_job_resume(int snum
, struct printjob
*pjob
)
761 TALLOC_CTX
*frame
= talloc_stackframe();
762 int ret
= 1; /* Return value */
763 http_t
*http
= NULL
; /* HTTP connection to server */
764 ipp_t
*request
= NULL
, /* IPP Request */
765 *response
= NULL
; /* IPP Response */
766 cups_lang_t
*language
= NULL
; /* Default language */
768 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
771 DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum
, pjob
, pjob
->sysjob
));
774 * Make sure we don't ask for passwords...
777 cupsSetPasswordCB(cups_passwd_cb
);
780 * Try to connect to the server...
783 if ((http
= cups_connect(frame
)) == NULL
) {
788 * Build an IPP_RELEASE_JOB request, which requires the following
792 * attributes-natural-language
794 * requesting-user-name
799 request
->request
.op
.operation_id
= IPP_RELEASE_JOB
;
800 request
->request
.op
.request_id
= 1;
802 language
= cupsLangDefault();
804 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
805 "attributes-charset", NULL
, "utf-8");
807 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
808 "attributes-natural-language", NULL
, language
->language
);
810 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/jobs/%d", pjob
->sysjob
);
812 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
814 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
817 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
821 * Do the request and get back a response...
824 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
) {
825 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
826 DEBUG(0,("Unable to release job %d - %s\n", pjob
->sysjob
,
827 ippErrorString(cupsLastError())));
832 DEBUG(0,("Unable to release job %d - %s\n", pjob
->sysjob
,
833 ippErrorString(cupsLastError())));
841 cupsLangFree(language
);
852 * 'cups_job_submit()' - Submit a job for printing.
855 static int cups_job_submit(int snum
, struct printjob
*pjob
,
856 enum printing_types printing_type
,
859 TALLOC_CTX
*frame
= talloc_stackframe();
860 int ret
= 1; /* Return value */
861 http_t
*http
= NULL
; /* HTTP connection to server */
862 ipp_t
*request
= NULL
, /* IPP Request */
863 *response
= NULL
; /* IPP Response */
864 ipp_attribute_t
*attr_job_id
= NULL
; /* IPP Attribute "job-id" */
865 cups_lang_t
*language
= NULL
; /* Default language */
866 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
867 char *new_jobname
= NULL
;
869 cups_option_t
*options
= NULL
;
870 char *printername
= NULL
;
872 char *jobname
= NULL
;
873 char *cupsoptions
= NULL
;
874 char *filename
= NULL
;
877 DEBUG(5,("cups_job_submit(%d, %p)\n", snum
, pjob
));
880 * Make sure we don't ask for passwords...
883 cupsSetPasswordCB(cups_passwd_cb
);
886 * Try to connect to the server...
889 if ((http
= cups_connect(frame
)) == NULL
) {
894 * Build an IPP_PRINT_JOB request, which requires the following
898 * attributes-natural-language
900 * requesting-user-name
906 request
->request
.op
.operation_id
= IPP_PRINT_JOB
;
907 request
->request
.op
.request_id
= 1;
909 language
= cupsLangDefault();
911 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
912 "attributes-charset", NULL
, "utf-8");
914 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
915 "attributes-natural-language", NULL
, language
->language
);
917 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
921 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
924 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
925 "printer-uri", NULL
, uri
);
927 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
930 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
933 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
934 "job-originating-host-name", NULL
,
935 pjob
->clientmachine
);
937 if (!push_utf8_talloc(frame
, &jobname
, pjob
->jobname
, &size
)) {
940 new_jobname
= talloc_asprintf(frame
,
941 "%s%.8u %s", PRINT_SPOOL_PREFIX
,
942 pjob
->jobid
, jobname
);
943 if (new_jobname
== NULL
) {
947 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
951 * add any options defined in smb.conf
954 if (!push_utf8_talloc(frame
, &cupsoptions
, lp_cups_options(snum
), &size
)) {
959 num_options
= cupsParseOptions(cupsoptions
, num_options
, &options
);
962 cupsEncodeOptions(request
, num_options
, options
);
965 * Do the request and get back a response...
968 slprintf(uri
, sizeof(uri
) - 1, "/printers/%s", printername
);
970 if (!push_utf8_talloc(frame
, &filename
, pjob
->filename
, &size
)) {
973 if ((response
= cupsDoFileRequest(http
, request
, uri
, pjob
->filename
)) != NULL
) {
974 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
975 DEBUG(0,("Unable to print file to %s - %s\n",
976 lp_printername(snum
),
977 ippErrorString(cupsLastError())));
980 attr_job_id
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
);
982 pjob
->sysjob
= attr_job_id
->values
[0].integer
;
983 DEBUG(5,("cups_job_submit: job-id %d\n", pjob
->sysjob
));
985 DEBUG(0,("Missing job-id attribute in IPP response"));
989 DEBUG(0,("Unable to print file to `%s' - %s\n",
990 lp_printername(snum
),
991 ippErrorString(cupsLastError())));
995 unlink(pjob
->filename
);
996 /* else print_job_end will do it for us */
1000 ippDelete(response
);
1003 cupsLangFree(language
);
1014 * 'cups_queue_get()' - Get all the jobs in the print queue.
1017 static int cups_queue_get(const char *sharename
,
1018 enum printing_types printing_type
,
1020 print_queue_struct
**q
,
1021 print_status_struct
*status
)
1023 TALLOC_CTX
*frame
= talloc_stackframe();
1024 char *printername
= NULL
;
1025 http_t
*http
= NULL
; /* HTTP connection to server */
1026 ipp_t
*request
= NULL
, /* IPP Request */
1027 *response
= NULL
; /* IPP Response */
1028 ipp_attribute_t
*attr
= NULL
; /* Current attribute */
1029 cups_lang_t
*language
= NULL
; /* Default language */
1030 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1031 int qcount
= 0, /* Number of active queue entries */
1032 qalloc
= 0; /* Number of queue entries allocated */
1033 print_queue_struct
*queue
= NULL
, /* Queue entries */
1034 *temp
; /* Temporary pointer for queue */
1035 char *user_name
= NULL
, /* job-originating-user-name attribute */
1036 *job_name
= NULL
; /* job-name attribute */
1037 int job_id
; /* job-id attribute */
1038 int job_k_octets
; /* job-k-octets attribute */
1039 time_t job_time
; /* time-at-creation attribute */
1040 ipp_jstate_t job_status
; /* job-status attribute */
1041 int job_priority
; /* job-priority attribute */
1043 static const char *jattrs
[] = /* Requested job attributes */
1048 "job-originating-user-name",
1053 static const char *pattrs
[] = /* Requested printer attributes */
1056 "printer-state-message"
1061 /* HACK ALERT!!! The problem with support the 'printer name'
1062 option is that we key the tdb off the sharename. So we will
1063 overload the lpq_command string to pass in the printername
1064 (which is basically what we do for non-cups printers ... using
1065 the lpq_command to get the queue listing). */
1067 if (!push_utf8_talloc(frame
, &printername
, lpq_command
, &size
)) {
1070 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command
, q
, status
));
1073 * Make sure we don't ask for passwords...
1076 cupsSetPasswordCB(cups_passwd_cb
);
1079 * Try to connect to the server...
1082 if ((http
= cups_connect(frame
)) == NULL
) {
1087 * Generate the printer URI...
1090 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s", printername
);
1093 * Build an IPP_GET_JOBS request, which requires the following
1096 * attributes-charset
1097 * attributes-natural-language
1098 * requested-attributes
1104 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
1105 request
->request
.op
.request_id
= 1;
1107 language
= cupsLangDefault();
1109 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1110 "attributes-charset", NULL
, "utf-8");
1112 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1113 "attributes-natural-language", NULL
, language
->language
);
1115 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1116 "requested-attributes",
1117 (sizeof(jattrs
) / sizeof(jattrs
[0])),
1120 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1121 "printer-uri", NULL
, uri
);
1124 * Do the request and get back a response...
1127 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1128 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1129 ippErrorString(cupsLastError())));
1133 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1134 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1135 ippErrorString(response
->request
.status
.status_code
)));
1140 * Process the jobs...
1147 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
) {
1149 * Skip leading attributes until we hit a job...
1152 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
1159 * Allocate memory as needed...
1161 if (qcount
>= qalloc
) {
1164 queue
= SMB_REALLOC_ARRAY(queue
, print_queue_struct
, qalloc
);
1166 if (queue
== NULL
) {
1167 DEBUG(0,("cups_queue_get: Not enough memory!"));
1173 temp
= queue
+ qcount
;
1174 memset(temp
, 0, sizeof(print_queue_struct
));
1177 * Pull the needed attributes from this job...
1182 job_status
= IPP_JOB_PENDING
;
1188 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
) {
1189 if (attr
->name
== NULL
) {
1194 if (strcmp(attr
->name
, "job-id") == 0 &&
1195 attr
->value_tag
== IPP_TAG_INTEGER
)
1196 job_id
= attr
->values
[0].integer
;
1198 if (strcmp(attr
->name
, "job-k-octets") == 0 &&
1199 attr
->value_tag
== IPP_TAG_INTEGER
)
1200 job_k_octets
= attr
->values
[0].integer
;
1202 if (strcmp(attr
->name
, "job-priority") == 0 &&
1203 attr
->value_tag
== IPP_TAG_INTEGER
)
1204 job_priority
= attr
->values
[0].integer
;
1206 if (strcmp(attr
->name
, "job-state") == 0 &&
1207 attr
->value_tag
== IPP_TAG_ENUM
)
1208 job_status
= (ipp_jstate_t
)(attr
->values
[0].integer
);
1210 if (strcmp(attr
->name
, "time-at-creation") == 0 &&
1211 attr
->value_tag
== IPP_TAG_INTEGER
)
1212 job_time
= attr
->values
[0].integer
;
1214 if (strcmp(attr
->name
, "job-name") == 0 &&
1215 attr
->value_tag
== IPP_TAG_NAME
) {
1216 if (!pull_utf8_talloc(frame
,
1218 attr
->values
[0].string
.text
,
1224 if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
1225 attr
->value_tag
== IPP_TAG_NAME
) {
1226 if (!pull_utf8_talloc(frame
,
1228 attr
->values
[0].string
.text
,
1238 * See if we have everything needed...
1241 if (user_name
== NULL
|| job_name
== NULL
|| job_id
== 0) {
1248 temp
->sysjob
= job_id
;
1249 temp
->size
= job_k_octets
* 1024;
1250 temp
->status
= job_status
== IPP_JOB_PENDING
? LPQ_QUEUED
:
1251 job_status
== IPP_JOB_STOPPED
? LPQ_PAUSED
:
1252 job_status
== IPP_JOB_HELD
? LPQ_PAUSED
:
1254 temp
->priority
= job_priority
;
1255 temp
->time
= job_time
;
1256 strlcpy(temp
->fs_user
, user_name
, sizeof(temp
->fs_user
));
1257 strlcpy(temp
->fs_file
, job_name
, sizeof(temp
->fs_file
));
1265 ippDelete(response
);
1269 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1270 * following attributes:
1272 * attributes-charset
1273 * attributes-natural-language
1274 * requested-attributes
1280 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1281 request
->request
.op
.request_id
= 1;
1283 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1284 "attributes-charset", NULL
, "utf-8");
1286 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1287 "attributes-natural-language", NULL
, language
->language
);
1289 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1290 "requested-attributes",
1291 (sizeof(pattrs
) / sizeof(pattrs
[0])),
1294 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1295 "printer-uri", NULL
, uri
);
1298 * Do the request and get back a response...
1301 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1302 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1303 ippErrorString(cupsLastError())));
1307 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1308 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1309 ippErrorString(response
->request
.status
.status_code
)));
1314 * Get the current printer status and convert it to the SAMBA values.
1317 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
) {
1318 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1319 status
->status
= LPSTAT_STOPPED
;
1321 status
->status
= LPSTAT_OK
;
1324 if ((attr
= ippFindAttribute(response
, "printer-state-message",
1325 IPP_TAG_TEXT
)) != NULL
) {
1327 if (!pull_utf8_talloc(frame
, &msg
,
1328 attr
->values
[0].string
.text
,
1334 fstrcpy(status
->message
, msg
);
1340 * Return the job queue...
1346 ippDelete(response
);
1349 cupsLangFree(language
);
1360 * 'cups_queue_pause()' - Pause a print queue.
1363 static int cups_queue_pause(int snum
)
1365 TALLOC_CTX
*frame
= talloc_stackframe();
1366 int ret
= 1; /* Return value */
1367 http_t
*http
= NULL
; /* HTTP connection to server */
1368 ipp_t
*request
= NULL
, /* IPP Request */
1369 *response
= NULL
; /* IPP Response */
1370 cups_lang_t
*language
= NULL
; /* Default language */
1371 char *printername
= NULL
;
1372 char *username
= NULL
;
1373 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1376 DEBUG(5,("cups_queue_pause(%d)\n", snum
));
1379 * Make sure we don't ask for passwords...
1382 cupsSetPasswordCB(cups_passwd_cb
);
1385 * Try to connect to the server...
1388 if ((http
= cups_connect(frame
)) == NULL
) {
1393 * Build an IPP_PAUSE_PRINTER request, which requires the following
1396 * attributes-charset
1397 * attributes-natural-language
1399 * requesting-user-name
1404 request
->request
.op
.operation_id
= IPP_PAUSE_PRINTER
;
1405 request
->request
.op
.request_id
= 1;
1407 language
= cupsLangDefault();
1409 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1410 "attributes-charset", NULL
, "utf-8");
1412 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1413 "attributes-natural-language", NULL
, language
->language
);
1415 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
1419 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1422 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1424 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1427 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1431 * Do the request and get back a response...
1434 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1435 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1436 DEBUG(0,("Unable to pause printer %s - %s\n",
1437 lp_printername(snum
),
1438 ippErrorString(cupsLastError())));
1443 DEBUG(0,("Unable to pause printer %s - %s\n",
1444 lp_printername(snum
),
1445 ippErrorString(cupsLastError())));
1450 ippDelete(response
);
1453 cupsLangFree(language
);
1464 * 'cups_queue_resume()' - Restart a print queue.
1467 static int cups_queue_resume(int snum
)
1469 TALLOC_CTX
*frame
= talloc_stackframe();
1470 int ret
= 1; /* Return value */
1471 http_t
*http
= NULL
; /* HTTP connection to server */
1472 ipp_t
*request
= NULL
, /* IPP Request */
1473 *response
= NULL
; /* IPP Response */
1474 cups_lang_t
*language
= NULL
; /* Default language */
1475 char *printername
= NULL
;
1476 char *username
= NULL
;
1477 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1480 DEBUG(5,("cups_queue_resume(%d)\n", snum
));
1483 * Make sure we don't ask for passwords...
1486 cupsSetPasswordCB(cups_passwd_cb
);
1489 * Try to connect to the server...
1492 if ((http
= cups_connect(frame
)) == NULL
) {
1497 * Build an IPP_RESUME_PRINTER request, which requires the following
1500 * attributes-charset
1501 * attributes-natural-language
1503 * requesting-user-name
1508 request
->request
.op
.operation_id
= IPP_RESUME_PRINTER
;
1509 request
->request
.op
.request_id
= 1;
1511 language
= cupsLangDefault();
1513 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1514 "attributes-charset", NULL
, "utf-8");
1516 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1517 "attributes-natural-language", NULL
, language
->language
);
1519 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
1523 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1526 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1528 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1531 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1535 * Do the request and get back a response...
1538 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1539 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1540 DEBUG(0,("Unable to resume printer %s - %s\n",
1541 lp_printername(snum
),
1542 ippErrorString(cupsLastError())));
1547 DEBUG(0,("Unable to resume printer %s - %s\n",
1548 lp_printername(snum
),
1549 ippErrorString(cupsLastError())));
1554 ippDelete(response
);
1557 cupsLangFree(language
);
1566 /*******************************************************************
1567 * CUPS printing interface definitions...
1568 ******************************************************************/
1570 struct printif cups_printif
=
1583 /* this keeps fussy compilers happy */
1584 void print_cups_dummy(void);
1585 void print_cups_dummy(void) {}
1586 #endif /* HAVE_CUPS */