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 "librpc/gen_ndr/ndr_printcap.h"
30 #include <cups/cups.h>
31 #include <cups/language.h>
33 static SIG_ATOMIC_T gotalarm
;
35 /***************************************************************
36 Signal function to tell us we timed out.
37 ****************************************************************/
39 static void gotalarm_sig(void)
44 extern userdom_struct current_user_info
;
47 * 'cups_passwd_cb()' - The CUPS password callback...
50 static const char * /* O - Password or NULL */
51 cups_passwd_cb(const char *prompt
) /* I - Prompt */
54 * Always return NULL to indicate that no password is available...
60 static http_t
*cups_connect(TALLOC_CTX
*frame
)
63 char *server
= NULL
, *p
= NULL
;
65 int timeout
= lp_cups_connection_timeout();
68 if (lp_cups_server() != NULL
&& strlen(lp_cups_server()) > 0) {
69 if (!push_utf8_talloc(frame
, &server
, lp_cups_server(), &size
)) {
73 server
= talloc_strdup(frame
,cupsServer());
79 p
= strchr(server
, ':');
87 DEBUG(10, ("connecting to cups server %s:%d\n",
93 CatchSignal(SIGALRM
, SIGNAL_CAST gotalarm_sig
);
97 #ifdef HAVE_HTTPCONNECTENCRYPT
98 http
= httpConnectEncrypt(server
, port
, lp_cups_encrypt());
100 http
= httpConnect(server
, port
);
104 CatchSignal(SIGALRM
, SIGNAL_CAST SIG_IGN
);
108 DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n",
109 server
, port
, strerror(errno
)));
115 static bool send_pcap_blob(DATA_BLOB
*pcap_blob
, int fd
)
119 ret
= sys_write(fd
, &pcap_blob
->length
, sizeof(pcap_blob
->length
));
120 if (ret
!= sizeof(pcap_blob
->length
)) {
124 ret
= sys_write(fd
, pcap_blob
->data
, pcap_blob
->length
);
125 if (ret
!= pcap_blob
->length
) {
129 DEBUG(10, ("successfully sent blob of len %ld\n", (int64_t)ret
));
133 static bool recv_pcap_blob(TALLOC_CTX
*mem_ctx
, int fd
, DATA_BLOB
*pcap_blob
)
138 ret
= sys_read(fd
, &blob_len
, sizeof(blob_len
));
139 if (ret
!= sizeof(blob_len
)) {
143 *pcap_blob
= data_blob_talloc_named(mem_ctx
, NULL
, blob_len
,
145 if (pcap_blob
->length
!= blob_len
) {
148 ret
= sys_read(fd
, pcap_blob
->data
, blob_len
);
149 if (ret
!= blob_len
) {
150 talloc_free(pcap_blob
->data
);
154 DEBUG(10, ("successfully recvd blob of len %ld\n", (int64_t)ret
));
158 static bool process_cups_printers_response(TALLOC_CTX
*mem_ctx
,
160 struct pcap_data
*pcap_data
)
162 ipp_attribute_t
*attr
;
165 struct pcap_printer
*printer
;
168 for (attr
= response
->attrs
; attr
!= NULL
;) {
170 * Skip leading attributes until we hit a printer...
173 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
180 * Pull the needed attributes from this printer...
186 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_PRINTER
) {
188 if (strcmp(attr
->name
, "printer-name") == 0 &&
189 attr
->value_tag
== IPP_TAG_NAME
) {
190 if (!pull_utf8_talloc(mem_ctx
,
192 attr
->values
[0].string
.text
,
198 if (strcmp(attr
->name
, "printer-info") == 0 &&
199 attr
->value_tag
== IPP_TAG_TEXT
) {
200 if (!pull_utf8_talloc(mem_ctx
,
202 attr
->values
[0].string
.text
,
212 * See if we have everything needed...
218 if (pcap_data
->count
== 0) {
219 printer
= talloc_array(mem_ctx
, struct pcap_printer
, 1);
221 printer
= talloc_realloc(mem_ctx
, pcap_data
->printers
,
223 pcap_data
->count
+ 1);
225 if (printer
== NULL
) {
228 pcap_data
->printers
= printer
;
229 pcap_data
->printers
[pcap_data
->count
].name
= name
;
230 pcap_data
->printers
[pcap_data
->count
].info
= info
;
240 * request printer list from cups, send result back to up parent via fd.
241 * returns true if the (possibly failed) result was successfuly sent to parent.
243 static bool cups_cache_reload_async(int fd
)
245 TALLOC_CTX
*frame
= talloc_stackframe();
246 struct pcap_data pcap_data
;
247 http_t
*http
= NULL
; /* HTTP connection to server */
248 ipp_t
*request
= NULL
, /* IPP Request */
249 *response
= NULL
; /* IPP Response */
250 cups_lang_t
*language
= NULL
; /* Default language */
251 static const char *requested
[] =/* Requested attributes */
257 enum ndr_err_code ndr_ret
;
260 ZERO_STRUCT(pcap_data
);
261 pcap_data
.status
= NT_STATUS_UNSUCCESSFUL
;
263 DEBUG(5, ("reloading cups printcap cache\n"));
266 * Make sure we don't ask for passwords...
269 cupsSetPasswordCB(cups_passwd_cb
);
271 if ((http
= cups_connect(frame
)) == NULL
) {
276 * Build a CUPS_GET_PRINTERS request, which requires the following
280 * attributes-natural-language
281 * requested-attributes
286 request
->request
.op
.operation_id
= CUPS_GET_PRINTERS
;
287 request
->request
.op
.request_id
= 1;
289 language
= cupsLangDefault();
291 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
292 "attributes-charset", NULL
, "utf-8");
294 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
295 "attributes-natural-language", NULL
, language
->language
);
297 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
298 "requested-attributes",
299 (sizeof(requested
) / sizeof(requested
[0])),
302 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
303 DEBUG(0,("Unable to get printer list - %s\n",
304 ippErrorString(cupsLastError())));
308 ret
= process_cups_printers_response(frame
, response
, &pcap_data
);
310 DEBUG(0,("failed to process cups response\n"));
318 * Build a CUPS_GET_CLASSES request, which requires the following
322 * attributes-natural-language
323 * requested-attributes
328 request
->request
.op
.operation_id
= CUPS_GET_CLASSES
;
329 request
->request
.op
.request_id
= 1;
331 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
332 "attributes-charset", NULL
, "utf-8");
334 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
335 "attributes-natural-language", NULL
, language
->language
);
337 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
338 "requested-attributes",
339 (sizeof(requested
) / sizeof(requested
[0])),
342 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
343 DEBUG(0,("Unable to get printer list - %s\n",
344 ippErrorString(cupsLastError())));
348 ret
= process_cups_printers_response(frame
, response
, &pcap_data
);
350 DEBUG(0,("failed to process cups response\n"));
354 pcap_data
.status
= NT_STATUS_OK
;
360 cupsLangFree(language
);
366 ndr_ret
= ndr_push_struct_blob(&pcap_blob
, frame
, NULL
, &pcap_data
,
367 (ndr_push_flags_fn_t
)ndr_push_pcap_data
);
368 if (ndr_ret
== NDR_ERR_SUCCESS
) {
369 ret
= send_pcap_blob(&pcap_blob
, fd
);
376 static struct pcap_cache
*local_pcap_copy
;
377 struct fd_event
*cache_fd_event
;
379 static bool cups_pcap_load_async(int *pfd
)
386 if (cache_fd_event
) {
387 DEBUG(3,("cups_pcap_load_async: already waiting for "
388 "a refresh event\n" ));
392 DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n"));
394 if (pipe(fds
) == -1) {
399 if (pid
== (pid_t
)-1) {
400 DEBUG(10,("cups_pcap_load_async: fork failed %s\n",
408 DEBUG(10,("cups_pcap_load_async: child pid = %u\n",
409 (unsigned int)pid
));
418 close_all_print_db();
420 if (!NT_STATUS_IS_OK(reinit_after_fork(smbd_messaging_context(),
421 smbd_event_context(), true))) {
422 DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
423 smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
427 cups_cache_reload_async(fds
[1]);
432 struct cups_async_cb_args
{
434 void (*post_cache_fill_fn
)(void);
437 static void cups_async_callback(struct event_context
*event_ctx
,
438 struct fd_event
*event
,
442 TALLOC_CTX
*frame
= talloc_stackframe();
443 struct cups_async_cb_args
*cb_args
= (struct cups_async_cb_args
*)p
;
444 struct pcap_cache
*tmp_pcap_cache
= NULL
;
446 struct pcap_data pcap_data
;
448 enum ndr_err_code ndr_ret
;
451 DEBUG(5,("cups_async_callback: callback received for printer data. "
452 "fd = %d\n", cb_args
->pipe_fd
));
454 ret_ok
= recv_pcap_blob(frame
, cb_args
->pipe_fd
, &pcap_blob
);
456 DEBUG(0,("failed to recv pcap blob\n"));
460 ndr_ret
= ndr_pull_struct_blob(&pcap_blob
, frame
, NULL
, &pcap_data
,
461 (ndr_pull_flags_fn_t
)ndr_pull_pcap_data
);
462 if (ndr_ret
!= NDR_ERR_SUCCESS
) {
466 if (!NT_STATUS_IS_OK(pcap_data
.status
)) {
467 DEBUG(0,("failed to retrieve printer list: %s\n",
468 nt_errstr(pcap_data
.status
)));
472 for (i
= 0; i
< pcap_data
.count
; i
++) {
473 ret_ok
= pcap_cache_add_specific(&tmp_pcap_cache
,
474 pcap_data
.printers
[i
].name
,
475 pcap_data
.printers
[i
].info
);
477 DEBUG(0, ("failed to add to tmp pcap cache\n"));
483 DEBUG(0,("failed to read a new printer list\n"));
484 pcap_cache_destroy_specific(&tmp_pcap_cache
);
486 /* We got a possibly empty namelist, replace our local cache. */
487 pcap_cache_destroy_specific(&local_pcap_copy
);
488 local_pcap_copy
= tmp_pcap_cache
;
490 /* And the systemwide pcap cache. */
491 pcap_cache_replace(local_pcap_copy
);
493 /* Caller may have requested post cache fill callback */
494 if (cb_args
->post_cache_fill_fn
) {
495 cb_args
->post_cache_fill_fn();
500 close(cb_args
->pipe_fd
);
501 TALLOC_FREE(cb_args
);
502 TALLOC_FREE(cache_fd_event
);
505 bool cups_cache_reload(void (*post_cache_fill_fn
)(void))
507 struct cups_async_cb_args
*cb_args
;
510 cb_args
= TALLOC_P(NULL
, struct cups_async_cb_args
);
514 cb_args
->post_cache_fill_fn
= post_cache_fill_fn
;
515 p_pipe_fd
= &cb_args
->pipe_fd
;
518 /* Set up an async refresh. */
519 if (!cups_pcap_load_async(p_pipe_fd
)) {
520 talloc_free(cb_args
);
523 if (!local_pcap_copy
) {
524 /* We have no local cache, wait directly for
525 * async refresh to complete.
527 DEBUG(10,("cups_cache_reload: sync read on fd %d\n",
530 cups_async_callback(smbd_event_context(),
534 if (!local_pcap_copy
) {
538 /* Replace the system cache with our
540 pcap_cache_replace(local_pcap_copy
);
542 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
545 /* Trigger an event when the pipe can be read. */
546 cache_fd_event
= event_add_fd(smbd_event_context(),
551 if (!cache_fd_event
) {
553 talloc_free(cb_args
);
561 * 'cups_job_delete()' - Delete a job.
564 static int cups_job_delete(const char *sharename
, const char *lprm_command
, struct printjob
*pjob
)
566 TALLOC_CTX
*frame
= talloc_stackframe();
567 int ret
= 1; /* Return value */
568 http_t
*http
= NULL
; /* HTTP connection to server */
569 ipp_t
*request
= NULL
, /* IPP Request */
570 *response
= NULL
; /* IPP Response */
571 cups_lang_t
*language
= NULL
; /* Default language */
573 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
576 DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename
, pjob
, pjob
->sysjob
));
579 * Make sure we don't ask for passwords...
582 cupsSetPasswordCB(cups_passwd_cb
);
585 * Try to connect to the server...
588 if ((http
= cups_connect(frame
)) == NULL
) {
593 * Build an IPP_CANCEL_JOB request, which requires the following
597 * attributes-natural-language
599 * requesting-user-name
604 request
->request
.op
.operation_id
= IPP_CANCEL_JOB
;
605 request
->request
.op
.request_id
= 1;
607 language
= cupsLangDefault();
609 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
610 "attributes-charset", NULL
, "utf-8");
612 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
613 "attributes-natural-language", NULL
, language
->language
);
615 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/jobs/%d", pjob
->sysjob
);
617 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
619 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
623 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
627 * Do the request and get back a response...
630 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
) {
631 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
632 DEBUG(0,("Unable to cancel job %d - %s\n", pjob
->sysjob
,
633 ippErrorString(cupsLastError())));
638 DEBUG(0,("Unable to cancel job %d - %s\n", pjob
->sysjob
,
639 ippErrorString(cupsLastError())));
647 cupsLangFree(language
);
658 * 'cups_job_pause()' - Pause a job.
661 static int cups_job_pause(int snum
, struct printjob
*pjob
)
663 TALLOC_CTX
*frame
= talloc_stackframe();
664 int ret
= 1; /* Return value */
665 http_t
*http
= NULL
; /* HTTP connection to server */
666 ipp_t
*request
= NULL
, /* IPP Request */
667 *response
= NULL
; /* IPP Response */
668 cups_lang_t
*language
= NULL
; /* Default language */
670 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
673 DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum
, pjob
, pjob
->sysjob
));
676 * Make sure we don't ask for passwords...
679 cupsSetPasswordCB(cups_passwd_cb
);
682 * Try to connect to the server...
685 if ((http
= cups_connect(frame
)) == NULL
) {
690 * Build an IPP_HOLD_JOB request, which requires the following
694 * attributes-natural-language
696 * requesting-user-name
701 request
->request
.op
.operation_id
= IPP_HOLD_JOB
;
702 request
->request
.op
.request_id
= 1;
704 language
= cupsLangDefault();
706 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
707 "attributes-charset", NULL
, "utf-8");
709 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
710 "attributes-natural-language", NULL
, language
->language
);
712 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/jobs/%d", pjob
->sysjob
);
714 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
716 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
719 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
723 * Do the request and get back a response...
726 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
) {
727 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
728 DEBUG(0,("Unable to hold job %d - %s\n", pjob
->sysjob
,
729 ippErrorString(cupsLastError())));
734 DEBUG(0,("Unable to hold job %d - %s\n", pjob
->sysjob
,
735 ippErrorString(cupsLastError())));
743 cupsLangFree(language
);
754 * 'cups_job_resume()' - Resume a paused job.
757 static int cups_job_resume(int snum
, struct printjob
*pjob
)
759 TALLOC_CTX
*frame
= talloc_stackframe();
760 int ret
= 1; /* Return value */
761 http_t
*http
= NULL
; /* HTTP connection to server */
762 ipp_t
*request
= NULL
, /* IPP Request */
763 *response
= NULL
; /* IPP Response */
764 cups_lang_t
*language
= NULL
; /* Default language */
766 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
769 DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum
, pjob
, pjob
->sysjob
));
772 * Make sure we don't ask for passwords...
775 cupsSetPasswordCB(cups_passwd_cb
);
778 * Try to connect to the server...
781 if ((http
= cups_connect(frame
)) == NULL
) {
786 * Build an IPP_RELEASE_JOB request, which requires the following
790 * attributes-natural-language
792 * requesting-user-name
797 request
->request
.op
.operation_id
= IPP_RELEASE_JOB
;
798 request
->request
.op
.request_id
= 1;
800 language
= cupsLangDefault();
802 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
803 "attributes-charset", NULL
, "utf-8");
805 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
806 "attributes-natural-language", NULL
, language
->language
);
808 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/jobs/%d", pjob
->sysjob
);
810 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
812 if (!push_utf8_talloc(frame
, &user
, pjob
->user
, &size
)) {
815 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
819 * Do the request and get back a response...
822 if ((response
= cupsDoRequest(http
, request
, "/jobs")) != NULL
) {
823 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
824 DEBUG(0,("Unable to release job %d - %s\n", pjob
->sysjob
,
825 ippErrorString(cupsLastError())));
830 DEBUG(0,("Unable to release job %d - %s\n", pjob
->sysjob
,
831 ippErrorString(cupsLastError())));
839 cupsLangFree(language
);
850 * 'cups_job_submit()' - Submit a job for printing.
853 static int cups_job_submit(int snum
, struct printjob
*pjob
)
855 TALLOC_CTX
*frame
= talloc_stackframe();
856 int ret
= 1; /* Return value */
857 http_t
*http
= NULL
; /* HTTP connection to server */
858 ipp_t
*request
= NULL
, /* IPP Request */
859 *response
= NULL
; /* IPP Response */
860 ipp_attribute_t
*attr_job_id
= NULL
; /* IPP Attribute "job-id" */
861 cups_lang_t
*language
= NULL
; /* Default language */
862 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
863 const char *clientname
= NULL
; /* hostname of client for job-originating-host attribute */
864 char *new_jobname
= NULL
;
866 cups_option_t
*options
= NULL
;
867 char *printername
= NULL
;
869 char *jobname
= NULL
;
870 char *cupsoptions
= NULL
;
871 char *filename
= NULL
;
873 uint32_t jobid
= (uint32_t)-1;
874 char addr
[INET6_ADDRSTRLEN
];
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
, PRINTERNAME(snum
), &size
)) {
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 clientname
= client_name(get_client_fd());
932 if (strcmp(clientname
, "UNKNOWN") == 0) {
933 clientname
= client_addr(get_client_fd(),addr
,sizeof(addr
));
936 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
937 "job-originating-host-name", NULL
,
940 /* Get the jobid from the filename. */
941 jobid
= print_parse_jobid(pjob
->filename
);
942 if (jobid
== (uint32_t)-1) {
943 DEBUG(0,("cups_job_submit: failed to parse jobid from name %s\n",
948 if (!push_utf8_talloc(frame
, &jobname
, pjob
->jobname
, &size
)) {
951 new_jobname
= talloc_asprintf(frame
,
952 "%s%.8u %s", PRINT_SPOOL_PREFIX
,
955 if (new_jobname
== NULL
) {
959 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "job-name", NULL
,
963 * add any options defined in smb.conf
966 if (!push_utf8_talloc(frame
, &cupsoptions
, lp_cups_options(snum
), &size
)) {
971 num_options
= cupsParseOptions(cupsoptions
, num_options
, &options
);
974 cupsEncodeOptions(request
, num_options
, options
);
977 * Do the request and get back a response...
980 slprintf(uri
, sizeof(uri
) - 1, "/printers/%s", printername
);
982 if (!push_utf8_talloc(frame
, &filename
, pjob
->filename
, &size
)) {
985 if ((response
= cupsDoFileRequest(http
, request
, uri
, pjob
->filename
)) != NULL
) {
986 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
987 DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum
),
988 ippErrorString(cupsLastError())));
991 attr_job_id
= ippFindAttribute(response
, "job-id", IPP_TAG_INTEGER
);
993 pjob
->sysjob
= attr_job_id
->values
[0].integer
;
994 DEBUG(5,("cups_job_submit: job-id %d\n", pjob
->sysjob
));
996 DEBUG(0,("Missing job-id attribute in IPP response"));
1000 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum
),
1001 ippErrorString(cupsLastError())));
1005 unlink(pjob
->filename
);
1006 /* else print_job_end will do it for us */
1010 ippDelete(response
);
1013 cupsLangFree(language
);
1024 * 'cups_queue_get()' - Get all the jobs in the print queue.
1027 static int cups_queue_get(const char *sharename
,
1028 enum printing_types printing_type
,
1030 print_queue_struct
**q
,
1031 print_status_struct
*status
)
1033 TALLOC_CTX
*frame
= talloc_stackframe();
1034 char *printername
= NULL
;
1035 http_t
*http
= NULL
; /* HTTP connection to server */
1036 ipp_t
*request
= NULL
, /* IPP Request */
1037 *response
= NULL
; /* IPP Response */
1038 ipp_attribute_t
*attr
= NULL
; /* Current attribute */
1039 cups_lang_t
*language
= NULL
; /* Default language */
1040 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1041 int qcount
= 0, /* Number of active queue entries */
1042 qalloc
= 0; /* Number of queue entries allocated */
1043 print_queue_struct
*queue
= NULL
, /* Queue entries */
1044 *temp
; /* Temporary pointer for queue */
1045 char *user_name
= NULL
, /* job-originating-user-name attribute */
1046 *job_name
= NULL
; /* job-name attribute */
1047 int job_id
; /* job-id attribute */
1048 int job_k_octets
; /* job-k-octets attribute */
1049 time_t job_time
; /* time-at-creation attribute */
1050 ipp_jstate_t job_status
; /* job-status attribute */
1051 int job_priority
; /* job-priority attribute */
1053 static const char *jattrs
[] = /* Requested job attributes */
1058 "job-originating-user-name",
1063 static const char *pattrs
[] = /* Requested printer attributes */
1066 "printer-state-message"
1071 /* HACK ALERT!!! The problem with support the 'printer name'
1072 option is that we key the tdb off the sharename. So we will
1073 overload the lpq_command string to pass in the printername
1074 (which is basically what we do for non-cups printers ... using
1075 the lpq_command to get the queue listing). */
1077 if (!push_utf8_talloc(frame
, &printername
, lpq_command
, &size
)) {
1080 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command
, q
, status
));
1083 * Make sure we don't ask for passwords...
1086 cupsSetPasswordCB(cups_passwd_cb
);
1089 * Try to connect to the server...
1092 if ((http
= cups_connect(frame
)) == NULL
) {
1097 * Generate the printer URI...
1100 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s", printername
);
1103 * Build an IPP_GET_JOBS request, which requires the following
1106 * attributes-charset
1107 * attributes-natural-language
1108 * requested-attributes
1114 request
->request
.op
.operation_id
= IPP_GET_JOBS
;
1115 request
->request
.op
.request_id
= 1;
1117 language
= cupsLangDefault();
1119 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1120 "attributes-charset", NULL
, "utf-8");
1122 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1123 "attributes-natural-language", NULL
, language
->language
);
1125 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1126 "requested-attributes",
1127 (sizeof(jattrs
) / sizeof(jattrs
[0])),
1130 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1131 "printer-uri", NULL
, uri
);
1134 * Do the request and get back a response...
1137 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1138 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1139 ippErrorString(cupsLastError())));
1143 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1144 DEBUG(0,("Unable to get jobs for %s - %s\n", uri
,
1145 ippErrorString(response
->request
.status
.status_code
)));
1150 * Process the jobs...
1157 for (attr
= response
->attrs
; attr
!= NULL
; attr
= attr
->next
) {
1159 * Skip leading attributes until we hit a job...
1162 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_JOB
)
1169 * Allocate memory as needed...
1171 if (qcount
>= qalloc
) {
1174 queue
= SMB_REALLOC_ARRAY(queue
, print_queue_struct
, qalloc
);
1176 if (queue
== NULL
) {
1177 DEBUG(0,("cups_queue_get: Not enough memory!"));
1183 temp
= queue
+ qcount
;
1184 memset(temp
, 0, sizeof(print_queue_struct
));
1187 * Pull the needed attributes from this job...
1192 job_status
= IPP_JOB_PENDING
;
1198 while (attr
!= NULL
&& attr
->group_tag
== IPP_TAG_JOB
) {
1199 if (attr
->name
== NULL
) {
1204 if (strcmp(attr
->name
, "job-id") == 0 &&
1205 attr
->value_tag
== IPP_TAG_INTEGER
)
1206 job_id
= attr
->values
[0].integer
;
1208 if (strcmp(attr
->name
, "job-k-octets") == 0 &&
1209 attr
->value_tag
== IPP_TAG_INTEGER
)
1210 job_k_octets
= attr
->values
[0].integer
;
1212 if (strcmp(attr
->name
, "job-priority") == 0 &&
1213 attr
->value_tag
== IPP_TAG_INTEGER
)
1214 job_priority
= attr
->values
[0].integer
;
1216 if (strcmp(attr
->name
, "job-state") == 0 &&
1217 attr
->value_tag
== IPP_TAG_ENUM
)
1218 job_status
= (ipp_jstate_t
)(attr
->values
[0].integer
);
1220 if (strcmp(attr
->name
, "time-at-creation") == 0 &&
1221 attr
->value_tag
== IPP_TAG_INTEGER
)
1222 job_time
= attr
->values
[0].integer
;
1224 if (strcmp(attr
->name
, "job-name") == 0 &&
1225 attr
->value_tag
== IPP_TAG_NAME
) {
1226 if (!pull_utf8_talloc(frame
,
1228 attr
->values
[0].string
.text
,
1234 if (strcmp(attr
->name
, "job-originating-user-name") == 0 &&
1235 attr
->value_tag
== IPP_TAG_NAME
) {
1236 if (!pull_utf8_talloc(frame
,
1238 attr
->values
[0].string
.text
,
1248 * See if we have everything needed...
1251 if (user_name
== NULL
|| job_name
== NULL
|| job_id
== 0) {
1259 temp
->size
= job_k_octets
* 1024;
1260 temp
->status
= job_status
== IPP_JOB_PENDING
? LPQ_QUEUED
:
1261 job_status
== IPP_JOB_STOPPED
? LPQ_PAUSED
:
1262 job_status
== IPP_JOB_HELD
? LPQ_PAUSED
:
1264 temp
->priority
= job_priority
;
1265 temp
->time
= job_time
;
1266 strlcpy(temp
->fs_user
, user_name
, sizeof(temp
->fs_user
));
1267 strlcpy(temp
->fs_file
, job_name
, sizeof(temp
->fs_file
));
1275 ippDelete(response
);
1279 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1280 * following attributes:
1282 * attributes-charset
1283 * attributes-natural-language
1284 * requested-attributes
1290 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1291 request
->request
.op
.request_id
= 1;
1293 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1294 "attributes-charset", NULL
, "utf-8");
1296 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1297 "attributes-natural-language", NULL
, language
->language
);
1299 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1300 "requested-attributes",
1301 (sizeof(pattrs
) / sizeof(pattrs
[0])),
1304 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1305 "printer-uri", NULL
, uri
);
1308 * Do the request and get back a response...
1311 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1312 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1313 ippErrorString(cupsLastError())));
1317 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1318 DEBUG(0,("Unable to get printer status for %s - %s\n", printername
,
1319 ippErrorString(response
->request
.status
.status_code
)));
1324 * Get the current printer status and convert it to the SAMBA values.
1327 if ((attr
= ippFindAttribute(response
, "printer-state", IPP_TAG_ENUM
)) != NULL
) {
1328 if (attr
->values
[0].integer
== IPP_PRINTER_STOPPED
)
1329 status
->status
= LPSTAT_STOPPED
;
1331 status
->status
= LPSTAT_OK
;
1334 if ((attr
= ippFindAttribute(response
, "printer-state-message",
1335 IPP_TAG_TEXT
)) != NULL
) {
1337 if (!pull_utf8_talloc(frame
, &msg
,
1338 attr
->values
[0].string
.text
,
1344 fstrcpy(status
->message
, msg
);
1350 * Return the job queue...
1356 ippDelete(response
);
1359 cupsLangFree(language
);
1370 * 'cups_queue_pause()' - Pause a print queue.
1373 static int cups_queue_pause(int snum
)
1375 TALLOC_CTX
*frame
= talloc_stackframe();
1376 int ret
= 1; /* Return value */
1377 http_t
*http
= NULL
; /* HTTP connection to server */
1378 ipp_t
*request
= NULL
, /* IPP Request */
1379 *response
= NULL
; /* IPP Response */
1380 cups_lang_t
*language
= NULL
; /* Default language */
1381 char *printername
= NULL
;
1382 char *username
= NULL
;
1383 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1386 DEBUG(5,("cups_queue_pause(%d)\n", snum
));
1389 * Make sure we don't ask for passwords...
1392 cupsSetPasswordCB(cups_passwd_cb
);
1395 * Try to connect to the server...
1398 if ((http
= cups_connect(frame
)) == NULL
) {
1403 * Build an IPP_PAUSE_PRINTER request, which requires the following
1406 * attributes-charset
1407 * attributes-natural-language
1409 * requesting-user-name
1414 request
->request
.op
.operation_id
= IPP_PAUSE_PRINTER
;
1415 request
->request
.op
.request_id
= 1;
1417 language
= cupsLangDefault();
1419 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1420 "attributes-charset", NULL
, "utf-8");
1422 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1423 "attributes-natural-language", NULL
, language
->language
);
1425 if (!push_utf8_talloc(frame
, &printername
, PRINTERNAME(snum
), &size
)) {
1428 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1431 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1433 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1436 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1440 * Do the request and get back a response...
1443 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1444 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1445 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum
),
1446 ippErrorString(cupsLastError())));
1451 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum
),
1452 ippErrorString(cupsLastError())));
1457 ippDelete(response
);
1460 cupsLangFree(language
);
1471 * 'cups_queue_resume()' - Restart a print queue.
1474 static int cups_queue_resume(int snum
)
1476 TALLOC_CTX
*frame
= talloc_stackframe();
1477 int ret
= 1; /* Return value */
1478 http_t
*http
= NULL
; /* HTTP connection to server */
1479 ipp_t
*request
= NULL
, /* IPP Request */
1480 *response
= NULL
; /* IPP Response */
1481 cups_lang_t
*language
= NULL
; /* Default language */
1482 char *printername
= NULL
;
1483 char *username
= NULL
;
1484 char uri
[HTTP_MAX_URI
]; /* printer-uri attribute */
1487 DEBUG(5,("cups_queue_resume(%d)\n", snum
));
1490 * Make sure we don't ask for passwords...
1493 cupsSetPasswordCB(cups_passwd_cb
);
1496 * Try to connect to the server...
1499 if ((http
= cups_connect(frame
)) == NULL
) {
1504 * Build an IPP_RESUME_PRINTER request, which requires the following
1507 * attributes-charset
1508 * attributes-natural-language
1510 * requesting-user-name
1515 request
->request
.op
.operation_id
= IPP_RESUME_PRINTER
;
1516 request
->request
.op
.request_id
= 1;
1518 language
= cupsLangDefault();
1520 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1521 "attributes-charset", NULL
, "utf-8");
1523 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1524 "attributes-natural-language", NULL
, language
->language
);
1526 if (!push_utf8_talloc(frame
, &printername
, PRINTERNAME(snum
), &size
)) {
1529 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1532 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "printer-uri", NULL
, uri
);
1534 if (!push_utf8_talloc(frame
, &username
, current_user_info
.unix_name
, &size
)) {
1537 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
, "requesting-user-name",
1541 * Do the request and get back a response...
1544 if ((response
= cupsDoRequest(http
, request
, "/admin/")) != NULL
) {
1545 if (response
->request
.status
.status_code
>= IPP_OK_CONFLICT
) {
1546 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum
),
1547 ippErrorString(cupsLastError())));
1552 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum
),
1553 ippErrorString(cupsLastError())));
1558 ippDelete(response
);
1561 cupsLangFree(language
);
1570 /*******************************************************************
1571 * CUPS printing interface definitions...
1572 ******************************************************************/
1574 struct printif cups_printif
=
1586 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2
*printer
)
1588 TALLOC_CTX
*frame
= talloc_stackframe();
1589 http_t
*http
= NULL
; /* HTTP connection to server */
1590 ipp_t
*request
= NULL
, /* IPP Request */
1591 *response
= NULL
; /* IPP Response */
1592 ipp_attribute_t
*attr
; /* Current attribute */
1593 cups_lang_t
*language
= NULL
; /* Default language */
1594 char uri
[HTTP_MAX_URI
];
1595 char *sharename
= NULL
;
1597 static const char *requested
[] =/* Requested attributes */
1606 DEBUG(5, ("pulling %s location\n", printer
->sharename
));
1609 * Make sure we don't ask for passwords...
1612 cupsSetPasswordCB(cups_passwd_cb
);
1615 * Try to connect to the server...
1618 if ((http
= cups_connect(frame
)) == NULL
) {
1624 request
->request
.op
.operation_id
= IPP_GET_PRINTER_ATTRIBUTES
;
1625 request
->request
.op
.request_id
= 1;
1627 language
= cupsLangDefault();
1629 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
1630 "attributes-charset", NULL
, "utf-8");
1632 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1633 "attributes-natural-language", NULL
, language
->language
);
1635 if (!push_utf8_talloc(frame
, &sharename
, printer
->sharename
, &size
)) {
1638 slprintf(uri
, sizeof(uri
) - 1, "ipp://localhost/printers/%s",
1641 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
,
1642 "printer-uri", NULL
, uri
);
1644 ippAddStrings(request
, IPP_TAG_OPERATION
, IPP_TAG_NAME
,
1645 "requested-attributes",
1646 (sizeof(requested
) / sizeof(requested
[0])),
1650 * Do the request and get back a response...
1653 if ((response
= cupsDoRequest(http
, request
, "/")) == NULL
) {
1654 DEBUG(0,("Unable to get printer attributes - %s\n",
1655 ippErrorString(cupsLastError())));
1659 for (attr
= response
->attrs
; attr
!= NULL
;) {
1661 * Skip leading attributes until we hit a printer...
1664 while (attr
!= NULL
&& attr
->group_tag
!= IPP_TAG_PRINTER
)
1671 * Pull the needed attributes from this printer...
1674 while ( attr
&& (attr
->group_tag
== IPP_TAG_PRINTER
) ) {
1675 if (strcmp(attr
->name
, "printer-name") == 0 &&
1676 attr
->value_tag
== IPP_TAG_NAME
) {
1677 if (!pull_utf8_talloc(frame
,
1679 attr
->values
[0].string
.text
,
1685 /* Grab the comment if we don't have one */
1686 if ( (strcmp(attr
->name
, "printer-info") == 0)
1687 && (attr
->value_tag
== IPP_TAG_TEXT
)
1688 && !strlen(printer
->comment
) )
1690 char *comment
= NULL
;
1691 if (!pull_utf8_talloc(frame
,
1693 attr
->values
[0].string
.text
,
1697 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1699 strlcpy(printer
->comment
,
1701 sizeof(printer
->comment
));
1704 /* Grab the location if we don't have one */
1705 if ( (strcmp(attr
->name
, "printer-location") == 0)
1706 && (attr
->value_tag
== IPP_TAG_TEXT
)
1707 && !strlen(printer
->location
) )
1709 char *location
= NULL
;
1710 if (!pull_utf8_talloc(frame
,
1712 attr
->values
[0].string
.text
,
1716 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1718 strlcpy(printer
->location
,
1720 sizeof(printer
->location
));
1727 * We have everything needed...
1738 ippDelete(response
);
1741 cupsLangFree(language
);
1751 /* this keeps fussy compilers happy */
1752 void print_cups_dummy(void);
1753 void print_cups_dummy(void) {}
1754 #endif /* HAVE_CUPS */