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
;
874 uint32_t jobid
= (uint32_t)-1;
876 DEBUG(5,("cups_job_submit(%d, %p)\n", snum
, pjob
));
879 * Make sure we don't ask for passwords...
882 cupsSetPasswordCB(cups_passwd_cb
);
885 * Try to connect to the server...
888 if ((http
= cups_connect(frame
)) == NULL
) {
893 * Build an IPP_PRINT_JOB request, which requires the following
897 * attributes-natural-language
899 * requesting-user-name
905 request
->request
.op
.operation_id
= IPP_PRINT_JOB
;
906 request
->request
.op
.request_id
= 1;
908 language
= cupsLangDefault();
910 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
911 "attributes-charset", NULL
, "utf-8");
913 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
914 "attributes-natural-language", NULL
, language
->language
);
916 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
920 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
923 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
924 "printer-uri", NULL
, uri
);
926 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
929 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
932 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
933 "job-originating-host-name", NULL
,
934 pjob
->clientmachine
);
936 /* Get the jobid from the filename. */
937 jobid
= print_parse_jobid(pjob
->filename
);
938 if (jobid
== (uint32_t)-1) {
939 DEBUG(0,("cups_job_submit: failed to parse jobid from name %s\n",
944 if (!push_utf8_talloc(frame
, &jobname
, pjob
->jobname
, &size
)) {
947 new_jobname
= talloc_asprintf(frame
,
948 "%s%.8u %s", PRINT_SPOOL_PREFIX
,
951 if (new_jobname
== NULL
) {
955 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
959 * add any options defined in smb.conf
962 if (!push_utf8_talloc(frame
, &cupsoptions
, lp_cups_options(snum
), &size
)) {
967 num_options
= cupsParseOptions(cupsoptions
, num_options
, &options
);
970 cupsEncodeOptions(request
, num_options
, options
);
973 * Do the request and get back a response...
976 slprintf(uri
, sizeof(uri
) - 1, "/printers/%s", printername
);
978 if (!push_utf8_talloc(frame
, &filename
, pjob
->filename
, &size
)) {
981 if ((response
= cupsDoFileRequest(http
, request
, uri
, pjob
->filename
)) != NULL
) {
982 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
983 DEBUG(0,("Unable to print file to %s - %s\n",
984 lp_printername(snum
),
985 ippErrorString(cupsLastError())));
988 attr_job_id
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
);
990 pjob
->sysjob
= attr_job_id
->values
[0].integer
;
991 DEBUG(5,("cups_job_submit: job-id %d\n", pjob
->sysjob
));
993 DEBUG(0,("Missing job-id attribute in IPP response"));
997 DEBUG(0,("Unable to print file to `%s' - %s\n",
998 lp_printername(snum
),
999 ippErrorString(cupsLastError())));
1003 unlink(pjob
->filename
);
1004 /* else print_job_end will do it for us */
1008 ippDelete(response
);
1011 cupsLangFree(language
);
1022 * 'cups_queue_get()' - Get all the jobs in the print queue.
1025 static int cups_queue_get(const char *sharename
,
1026 enum printing_types printing_type
,
1028 print_queue_struct
**q
,
1029 print_status_struct
*status
)
1031 TALLOC_CTX
*frame
= talloc_stackframe();
1032 char *printername
= NULL
;
1033 http_t
*http
= NULL
; /* HTTP connection to server */
1034 ipp_t
*request
= NULL
, /* IPP Request */
1035 *response
= NULL
; /* IPP Response */
1036 ipp_attribute_t
*attr
= NULL
; /* Current attribute */
1037 cups_lang_t
*language
= NULL
; /* Default language */
1038 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1039 int qcount
= 0, /* Number of active queue entries */
1040 qalloc
= 0; /* Number of queue entries allocated */
1041 print_queue_struct
*queue
= NULL
, /* Queue entries */
1042 *temp
; /* Temporary pointer for queue */
1043 char *user_name
= NULL
, /* job-originating-user-name attribute */
1044 *job_name
= NULL
; /* job-name attribute */
1045 int job_id
; /* job-id attribute */
1046 int job_k_octets
; /* job-k-octets attribute */
1047 time_t job_time
; /* time-at-creation attribute */
1048 ipp_jstate_t job_status
; /* job-status attribute */
1049 int job_priority
; /* job-priority attribute */
1051 static const char *jattrs
[] = /* Requested job attributes */
1056 "job-originating-user-name",
1061 static const char *pattrs
[] = /* Requested printer attributes */
1064 "printer-state-message"
1069 /* HACK ALERT!!! The problem with support the 'printer name'
1070 option is that we key the tdb off the sharename. So we will
1071 overload the lpq_command string to pass in the printername
1072 (which is basically what we do for non-cups printers ... using
1073 the lpq_command to get the queue listing). */
1075 if (!push_utf8_talloc(frame
, &printername
, lpq_command
, &size
)) {
1078 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command
, q
, status
));
1081 * Make sure we don't ask for passwords...
1084 cupsSetPasswordCB(cups_passwd_cb
);
1087 * Try to connect to the server...
1090 if ((http
= cups_connect(frame
)) == NULL
) {
1095 * Generate the printer URI...
1098 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s", printername
);
1101 * Build an IPP_GET_JOBS request, which requires the following
1104 * attributes-charset
1105 * attributes-natural-language
1106 * requested-attributes
1112 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
1113 request
->request
.op
.request_id
= 1;
1115 language
= cupsLangDefault();
1117 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1118 "attributes-charset", NULL
, "utf-8");
1120 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1121 "attributes-natural-language", NULL
, language
->language
);
1123 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1124 "requested-attributes",
1125 (sizeof(jattrs
) / sizeof(jattrs
[0])),
1128 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1129 "printer-uri", NULL
, uri
);
1132 * Do the request and get back a response...
1135 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1136 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1137 ippErrorString(cupsLastError())));
1141 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1142 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1143 ippErrorString(response
->request
.status
.status_code
)));
1148 * Process the jobs...
1155 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
) {
1157 * Skip leading attributes until we hit a job...
1160 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
1167 * Allocate memory as needed...
1169 if (qcount
>= qalloc
) {
1172 queue
= SMB_REALLOC_ARRAY(queue
, print_queue_struct
, qalloc
);
1174 if (queue
== NULL
) {
1175 DEBUG(0,("cups_queue_get: Not enough memory!"));
1181 temp
= queue
+ qcount
;
1182 memset(temp
, 0, sizeof(print_queue_struct
));
1185 * Pull the needed attributes from this job...
1190 job_status
= IPP_JOB_PENDING
;
1196 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
) {
1197 if (attr
->name
== NULL
) {
1202 if (strcmp(attr
->name
, "job-id") == 0 &&
1203 attr
->value_tag
== IPP_TAG_INTEGER
)
1204 job_id
= attr
->values
[0].integer
;
1206 if (strcmp(attr
->name
, "job-k-octets") == 0 &&
1207 attr
->value_tag
== IPP_TAG_INTEGER
)
1208 job_k_octets
= attr
->values
[0].integer
;
1210 if (strcmp(attr
->name
, "job-priority") == 0 &&
1211 attr
->value_tag
== IPP_TAG_INTEGER
)
1212 job_priority
= attr
->values
[0].integer
;
1214 if (strcmp(attr
->name
, "job-state") == 0 &&
1215 attr
->value_tag
== IPP_TAG_ENUM
)
1216 job_status
= (ipp_jstate_t
)(attr
->values
[0].integer
);
1218 if (strcmp(attr
->name
, "time-at-creation") == 0 &&
1219 attr
->value_tag
== IPP_TAG_INTEGER
)
1220 job_time
= attr
->values
[0].integer
;
1222 if (strcmp(attr
->name
, "job-name") == 0 &&
1223 attr
->value_tag
== IPP_TAG_NAME
) {
1224 if (!pull_utf8_talloc(frame
,
1226 attr
->values
[0].string
.text
,
1232 if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
1233 attr
->value_tag
== IPP_TAG_NAME
) {
1234 if (!pull_utf8_talloc(frame
,
1236 attr
->values
[0].string
.text
,
1246 * See if we have everything needed...
1249 if (user_name
== NULL
|| job_name
== NULL
|| job_id
== 0) {
1257 temp
->size
= job_k_octets
* 1024;
1258 temp
->status
= job_status
== IPP_JOB_PENDING
? LPQ_QUEUED
:
1259 job_status
== IPP_JOB_STOPPED
? LPQ_PAUSED
:
1260 job_status
== IPP_JOB_HELD
? LPQ_PAUSED
:
1262 temp
->priority
= job_priority
;
1263 temp
->time
= job_time
;
1264 strlcpy(temp
->fs_user
, user_name
, sizeof(temp
->fs_user
));
1265 strlcpy(temp
->fs_file
, job_name
, sizeof(temp
->fs_file
));
1273 ippDelete(response
);
1277 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1278 * following attributes:
1280 * attributes-charset
1281 * attributes-natural-language
1282 * requested-attributes
1288 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1289 request
->request
.op
.request_id
= 1;
1291 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1292 "attributes-charset", NULL
, "utf-8");
1294 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1295 "attributes-natural-language", NULL
, language
->language
);
1297 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1298 "requested-attributes",
1299 (sizeof(pattrs
) / sizeof(pattrs
[0])),
1302 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1303 "printer-uri", NULL
, uri
);
1306 * Do the request and get back a response...
1309 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1310 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1311 ippErrorString(cupsLastError())));
1315 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1316 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1317 ippErrorString(response
->request
.status
.status_code
)));
1322 * Get the current printer status and convert it to the SAMBA values.
1325 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
) {
1326 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1327 status
->status
= LPSTAT_STOPPED
;
1329 status
->status
= LPSTAT_OK
;
1332 if ((attr
= ippFindAttribute(response
, "printer-state-message",
1333 IPP_TAG_TEXT
)) != NULL
) {
1335 if (!pull_utf8_talloc(frame
, &msg
,
1336 attr
->values
[0].string
.text
,
1342 fstrcpy(status
->message
, msg
);
1348 * Return the job queue...
1354 ippDelete(response
);
1357 cupsLangFree(language
);
1368 * 'cups_queue_pause()' - Pause a print queue.
1371 static int cups_queue_pause(int snum
)
1373 TALLOC_CTX
*frame
= talloc_stackframe();
1374 int ret
= 1; /* Return value */
1375 http_t
*http
= NULL
; /* HTTP connection to server */
1376 ipp_t
*request
= NULL
, /* IPP Request */
1377 *response
= NULL
; /* IPP Response */
1378 cups_lang_t
*language
= NULL
; /* Default language */
1379 char *printername
= NULL
;
1380 char *username
= NULL
;
1381 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1384 DEBUG(5,("cups_queue_pause(%d)\n", snum
));
1387 * Make sure we don't ask for passwords...
1390 cupsSetPasswordCB(cups_passwd_cb
);
1393 * Try to connect to the server...
1396 if ((http
= cups_connect(frame
)) == NULL
) {
1401 * Build an IPP_PAUSE_PRINTER request, which requires the following
1404 * attributes-charset
1405 * attributes-natural-language
1407 * requesting-user-name
1412 request
->request
.op
.operation_id
= IPP_PAUSE_PRINTER
;
1413 request
->request
.op
.request_id
= 1;
1415 language
= cupsLangDefault();
1417 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1418 "attributes-charset", NULL
, "utf-8");
1420 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1421 "attributes-natural-language", NULL
, language
->language
);
1423 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
1427 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1430 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1432 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1435 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1439 * Do the request and get back a response...
1442 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1443 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1444 DEBUG(0,("Unable to pause printer %s - %s\n",
1445 lp_printername(snum
),
1446 ippErrorString(cupsLastError())));
1451 DEBUG(0,("Unable to pause printer %s - %s\n",
1452 lp_printername(snum
),
1453 ippErrorString(cupsLastError())));
1458 ippDelete(response
);
1461 cupsLangFree(language
);
1472 * 'cups_queue_resume()' - Restart a print queue.
1475 static int cups_queue_resume(int snum
)
1477 TALLOC_CTX
*frame
= talloc_stackframe();
1478 int ret
= 1; /* Return value */
1479 http_t
*http
= NULL
; /* HTTP connection to server */
1480 ipp_t
*request
= NULL
, /* IPP Request */
1481 *response
= NULL
; /* IPP Response */
1482 cups_lang_t
*language
= NULL
; /* Default language */
1483 char *printername
= NULL
;
1484 char *username
= NULL
;
1485 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1488 DEBUG(5,("cups_queue_resume(%d)\n", snum
));
1491 * Make sure we don't ask for passwords...
1494 cupsSetPasswordCB(cups_passwd_cb
);
1497 * Try to connect to the server...
1500 if ((http
= cups_connect(frame
)) == NULL
) {
1505 * Build an IPP_RESUME_PRINTER request, which requires the following
1508 * attributes-charset
1509 * attributes-natural-language
1511 * requesting-user-name
1516 request
->request
.op
.operation_id
= IPP_RESUME_PRINTER
;
1517 request
->request
.op
.request_id
= 1;
1519 language
= cupsLangDefault();
1521 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1522 "attributes-charset", NULL
, "utf-8");
1524 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1525 "attributes-natural-language", NULL
, language
->language
);
1527 if (!push_utf8_talloc(frame
, &printername
, lp_printername(snum
),
1531 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1534 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1536 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1539 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1543 * Do the request and get back a response...
1546 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1547 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1548 DEBUG(0,("Unable to resume printer %s - %s\n",
1549 lp_printername(snum
),
1550 ippErrorString(cupsLastError())));
1555 DEBUG(0,("Unable to resume printer %s - %s\n",
1556 lp_printername(snum
),
1557 ippErrorString(cupsLastError())));
1562 ippDelete(response
);
1565 cupsLangFree(language
);
1574 /*******************************************************************
1575 * CUPS printing interface definitions...
1576 ******************************************************************/
1578 struct printif cups_printif
=
1591 /* this keeps fussy compilers happy */
1592 void print_cups_dummy(void);
1593 void print_cups_dummy(void) {}
1594 #endif /* HAVE_CUPS */