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
)
857 TALLOC_CTX
*frame
= talloc_stackframe();
858 int ret
= 1; /* Return value */
859 http_t
*http
= NULL
; /* HTTP connection to server */
860 ipp_t
*request
= NULL
, /* IPP Request */
861 *response
= NULL
; /* IPP Response */
862 ipp_attribute_t
*attr_job_id
= NULL
; /* IPP Attribute "job-id" */
863 cups_lang_t
*language
= NULL
; /* Default language */
864 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
865 char *new_jobname
= NULL
;
867 cups_option_t
*options
= NULL
;
868 char *printername
= NULL
;
870 char *jobname
= NULL
;
871 char *cupsoptions
= NULL
;
872 char *filename
= NULL
;
875 DEBUG(5,("cups_job_submit(%d, %p)\n", snum
, pjob
));
878 * Make sure we don't ask for passwords...
881 cupsSetPasswordCB(cups_passwd_cb
);
884 * Try to connect to the server...
887 if ((http
= cups_connect(frame
)) == NULL
) {
892 * Build an IPP_PRINT_JOB request, which requires the following
896 * attributes-natural-language
898 * requesting-user-name
904 request
->request
.op
.operation_id
= IPP_PRINT_JOB
;
905 request
->request
.op
.request_id
= 1;
907 language
= cupsLangDefault();
909 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
910 "attributes-charset", NULL
, "utf-8");
912 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
913 "attributes-natural-language", NULL
, language
->language
);
915 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
919 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
922 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
923 "printer-uri", NULL
, uri
);
925 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
928 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
931 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
932 "job-originating-host-name", NULL
,
933 pjob
->clientmachine
);
935 if (!push_utf8_talloc(frame
, &jobname
, pjob
->jobname
, &size
)) {
938 new_jobname
= talloc_asprintf(frame
,
939 "%s%.8u %s", PRINT_SPOOL_PREFIX
,
940 pjob
->jobid
, jobname
);
941 if (new_jobname
== NULL
) {
945 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
949 * add any options defined in smb.conf
952 if (!push_utf8_talloc(frame
, &cupsoptions
, lp_cups_options(snum
), &size
)) {
957 num_options
= cupsParseOptions(cupsoptions
, num_options
, &options
);
960 cupsEncodeOptions(request
, num_options
, options
);
963 * Do the request and get back a response...
966 slprintf(uri
, sizeof(uri
) - 1, "/printers/%s", printername
);
968 if (!push_utf8_talloc(frame
, &filename
, pjob
->filename
, &size
)) {
971 if ((response
= cupsDoFileRequest(http
, request
, uri
, pjob
->filename
)) != NULL
) {
972 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
973 DEBUG(0,("Unable to print file to %s - %s\n",
974 lp_printername(snum
),
975 ippErrorString(cupsLastError())));
978 attr_job_id
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
);
980 pjob
->sysjob
= attr_job_id
->values
[0].integer
;
981 DEBUG(5,("cups_job_submit: job-id %d\n", pjob
->sysjob
));
983 DEBUG(0,("Missing job-id attribute in IPP response"));
987 DEBUG(0,("Unable to print file to `%s' - %s\n",
988 lp_printername(snum
),
989 ippErrorString(cupsLastError())));
993 unlink(pjob
->filename
);
994 /* else print_job_end will do it for us */
1001 cupsLangFree(language
);
1012 * 'cups_queue_get()' - Get all the jobs in the print queue.
1015 static int cups_queue_get(const char *sharename
,
1016 enum printing_types printing_type
,
1018 print_queue_struct
**q
,
1019 print_status_struct
*status
)
1021 TALLOC_CTX
*frame
= talloc_stackframe();
1022 char *printername
= NULL
;
1023 http_t
*http
= NULL
; /* HTTP connection to server */
1024 ipp_t
*request
= NULL
, /* IPP Request */
1025 *response
= NULL
; /* IPP Response */
1026 ipp_attribute_t
*attr
= NULL
; /* Current attribute */
1027 cups_lang_t
*language
= NULL
; /* Default language */
1028 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1029 int qcount
= 0, /* Number of active queue entries */
1030 qalloc
= 0; /* Number of queue entries allocated */
1031 print_queue_struct
*queue
= NULL
, /* Queue entries */
1032 *temp
; /* Temporary pointer for queue */
1033 char *user_name
= NULL
, /* job-originating-user-name attribute */
1034 *job_name
= NULL
; /* job-name attribute */
1035 int job_id
; /* job-id attribute */
1036 int job_k_octets
; /* job-k-octets attribute */
1037 time_t job_time
; /* time-at-creation attribute */
1038 ipp_jstate_t job_status
; /* job-status attribute */
1039 int job_priority
; /* job-priority attribute */
1041 static const char *jattrs
[] = /* Requested job attributes */
1046 "job-originating-user-name",
1051 static const char *pattrs
[] = /* Requested printer attributes */
1054 "printer-state-message"
1059 /* HACK ALERT!!! The problem with support the 'printer name'
1060 option is that we key the tdb off the sharename. So we will
1061 overload the lpq_command string to pass in the printername
1062 (which is basically what we do for non-cups printers ... using
1063 the lpq_command to get the queue listing). */
1065 if (!push_utf8_talloc(frame
, &printername
, lpq_command
, &size
)) {
1068 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command
, q
, status
));
1071 * Make sure we don't ask for passwords...
1074 cupsSetPasswordCB(cups_passwd_cb
);
1077 * Try to connect to the server...
1080 if ((http
= cups_connect(frame
)) == NULL
) {
1085 * Generate the printer URI...
1088 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s", printername
);
1091 * Build an IPP_GET_JOBS request, which requires the following
1094 * attributes-charset
1095 * attributes-natural-language
1096 * requested-attributes
1102 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
1103 request
->request
.op
.request_id
= 1;
1105 language
= cupsLangDefault();
1107 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1108 "attributes-charset", NULL
, "utf-8");
1110 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1111 "attributes-natural-language", NULL
, language
->language
);
1113 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1114 "requested-attributes",
1115 (sizeof(jattrs
) / sizeof(jattrs
[0])),
1118 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1119 "printer-uri", NULL
, uri
);
1122 * Do the request and get back a response...
1125 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1126 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1127 ippErrorString(cupsLastError())));
1131 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1132 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1133 ippErrorString(response
->request
.status
.status_code
)));
1138 * Process the jobs...
1145 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
) {
1147 * Skip leading attributes until we hit a job...
1150 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
1157 * Allocate memory as needed...
1159 if (qcount
>= qalloc
) {
1162 queue
= SMB_REALLOC_ARRAY(queue
, print_queue_struct
, qalloc
);
1164 if (queue
== NULL
) {
1165 DEBUG(0,("cups_queue_get: Not enough memory!"));
1171 temp
= queue
+ qcount
;
1172 memset(temp
, 0, sizeof(print_queue_struct
));
1175 * Pull the needed attributes from this job...
1180 job_status
= IPP_JOB_PENDING
;
1186 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
) {
1187 if (attr
->name
== NULL
) {
1192 if (strcmp(attr
->name
, "job-id") == 0 &&
1193 attr
->value_tag
== IPP_TAG_INTEGER
)
1194 job_id
= attr
->values
[0].integer
;
1196 if (strcmp(attr
->name
, "job-k-octets") == 0 &&
1197 attr
->value_tag
== IPP_TAG_INTEGER
)
1198 job_k_octets
= attr
->values
[0].integer
;
1200 if (strcmp(attr
->name
, "job-priority") == 0 &&
1201 attr
->value_tag
== IPP_TAG_INTEGER
)
1202 job_priority
= attr
->values
[0].integer
;
1204 if (strcmp(attr
->name
, "job-state") == 0 &&
1205 attr
->value_tag
== IPP_TAG_ENUM
)
1206 job_status
= (ipp_jstate_t
)(attr
->values
[0].integer
);
1208 if (strcmp(attr
->name
, "time-at-creation") == 0 &&
1209 attr
->value_tag
== IPP_TAG_INTEGER
)
1210 job_time
= attr
->values
[0].integer
;
1212 if (strcmp(attr
->name
, "job-name") == 0 &&
1213 attr
->value_tag
== IPP_TAG_NAME
) {
1214 if (!pull_utf8_talloc(frame
,
1216 attr
->values
[0].string
.text
,
1222 if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
1223 attr
->value_tag
== IPP_TAG_NAME
) {
1224 if (!pull_utf8_talloc(frame
,
1226 attr
->values
[0].string
.text
,
1236 * See if we have everything needed...
1239 if (user_name
== NULL
|| job_name
== NULL
|| job_id
== 0) {
1246 temp
->sysjob
= job_id
;
1247 temp
->size
= job_k_octets
* 1024;
1248 temp
->status
= job_status
== IPP_JOB_PENDING
? LPQ_QUEUED
:
1249 job_status
== IPP_JOB_STOPPED
? LPQ_PAUSED
:
1250 job_status
== IPP_JOB_HELD
? LPQ_PAUSED
:
1252 temp
->priority
= job_priority
;
1253 temp
->time
= job_time
;
1254 strlcpy(temp
->fs_user
, user_name
, sizeof(temp
->fs_user
));
1255 strlcpy(temp
->fs_file
, job_name
, sizeof(temp
->fs_file
));
1263 ippDelete(response
);
1267 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1268 * following attributes:
1270 * attributes-charset
1271 * attributes-natural-language
1272 * requested-attributes
1278 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1279 request
->request
.op
.request_id
= 1;
1281 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1282 "attributes-charset", NULL
, "utf-8");
1284 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1285 "attributes-natural-language", NULL
, language
->language
);
1287 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1288 "requested-attributes",
1289 (sizeof(pattrs
) / sizeof(pattrs
[0])),
1292 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1293 "printer-uri", NULL
, uri
);
1296 * Do the request and get back a response...
1299 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1300 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1301 ippErrorString(cupsLastError())));
1305 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1306 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1307 ippErrorString(response
->request
.status
.status_code
)));
1312 * Get the current printer status and convert it to the SAMBA values.
1315 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
) {
1316 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1317 status
->status
= LPSTAT_STOPPED
;
1319 status
->status
= LPSTAT_OK
;
1322 if ((attr
= ippFindAttribute(response
, "printer-state-message",
1323 IPP_TAG_TEXT
)) != NULL
) {
1325 if (!pull_utf8_talloc(frame
, &msg
,
1326 attr
->values
[0].string
.text
,
1332 fstrcpy(status
->message
, msg
);
1338 * Return the job queue...
1344 ippDelete(response
);
1347 cupsLangFree(language
);
1358 * 'cups_queue_pause()' - Pause a print queue.
1361 static int cups_queue_pause(int snum
)
1363 TALLOC_CTX
*frame
= talloc_stackframe();
1364 int ret
= 1; /* Return value */
1365 http_t
*http
= NULL
; /* HTTP connection to server */
1366 ipp_t
*request
= NULL
, /* IPP Request */
1367 *response
= NULL
; /* IPP Response */
1368 cups_lang_t
*language
= NULL
; /* Default language */
1369 char *printername
= NULL
;
1370 char *username
= NULL
;
1371 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1374 DEBUG(5,("cups_queue_pause(%d)\n", snum
));
1377 * Make sure we don't ask for passwords...
1380 cupsSetPasswordCB(cups_passwd_cb
);
1383 * Try to connect to the server...
1386 if ((http
= cups_connect(frame
)) == NULL
) {
1391 * Build an IPP_PAUSE_PRINTER request, which requires the following
1394 * attributes-charset
1395 * attributes-natural-language
1397 * requesting-user-name
1402 request
->request
.op
.operation_id
= IPP_PAUSE_PRINTER
;
1403 request
->request
.op
.request_id
= 1;
1405 language
= cupsLangDefault();
1407 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1408 "attributes-charset", NULL
, "utf-8");
1410 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1411 "attributes-natural-language", NULL
, language
->language
);
1413 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
1417 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1420 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1422 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1425 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1429 * Do the request and get back a response...
1432 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1433 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1434 DEBUG(0,("Unable to pause printer %s - %s\n",
1435 lp_printername(snum
),
1436 ippErrorString(cupsLastError())));
1441 DEBUG(0,("Unable to pause printer %s - %s\n",
1442 lp_printername(snum
),
1443 ippErrorString(cupsLastError())));
1448 ippDelete(response
);
1451 cupsLangFree(language
);
1462 * 'cups_queue_resume()' - Restart a print queue.
1465 static int cups_queue_resume(int snum
)
1467 TALLOC_CTX
*frame
= talloc_stackframe();
1468 int ret
= 1; /* Return value */
1469 http_t
*http
= NULL
; /* HTTP connection to server */
1470 ipp_t
*request
= NULL
, /* IPP Request */
1471 *response
= NULL
; /* IPP Response */
1472 cups_lang_t
*language
= NULL
; /* Default language */
1473 char *printername
= NULL
;
1474 char *username
= NULL
;
1475 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1478 DEBUG(5,("cups_queue_resume(%d)\n", snum
));
1481 * Make sure we don't ask for passwords...
1484 cupsSetPasswordCB(cups_passwd_cb
);
1487 * Try to connect to the server...
1490 if ((http
= cups_connect(frame
)) == NULL
) {
1495 * Build an IPP_RESUME_PRINTER request, which requires the following
1498 * attributes-charset
1499 * attributes-natural-language
1501 * requesting-user-name
1506 request
->request
.op
.operation_id
= IPP_RESUME_PRINTER
;
1507 request
->request
.op
.request_id
= 1;
1509 language
= cupsLangDefault();
1511 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1512 "attributes-charset", NULL
, "utf-8");
1514 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1515 "attributes-natural-language", NULL
, language
->language
);
1517 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
1521 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1524 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1526 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1529 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1533 * Do the request and get back a response...
1536 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1537 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1538 DEBUG(0,("Unable to resume printer %s - %s\n",
1539 lp_printername(snum
),
1540 ippErrorString(cupsLastError())));
1545 DEBUG(0,("Unable to resume printer %s - %s\n",
1546 lp_printername(snum
),
1547 ippErrorString(cupsLastError())));
1552 ippDelete(response
);
1555 cupsLangFree(language
);
1564 /*******************************************************************
1565 * CUPS printing interface definitions...
1566 ******************************************************************/
1568 struct printif cups_printif
=
1581 /* this keeps fussy compilers happy */
1582 void print_cups_dummy(void);
1583 void print_cups_dummy(void) {}
1584 #endif /* HAVE_CUPS */