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 struct pcap_printer *printer;
169 for (attr = response->attrs; attr != NULL;) {
171 * Skip leading attributes until we hit a printer...
174 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
181 * Pull the needed attributes from this printer...
187 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
189 if (strcmp(attr->name, "printer-name") == 0 &&
190 attr->value_tag == IPP_TAG_NAME) {
191 if (!pull_utf8_talloc(mem_ctx,
193 attr->values[0].string.text,
199 if (strcmp(attr->name, "printer-info") == 0 &&
200 attr->value_tag == IPP_TAG_TEXT) {
201 if (!pull_utf8_talloc(mem_ctx,
203 attr->values[0].string.text,
213 * See if we have everything needed...
219 if (pcap_data->count == 0) {
220 printer = talloc_array(mem_ctx, struct pcap_printer, 1);
222 printer = talloc_realloc(mem_ctx, pcap_data->printers,
224 pcap_data->count + 1);
226 if (printer == NULL) {
229 pcap_data->printers = printer;
230 pcap_data->printers[pcap_data->count].name = name;
231 pcap_data->printers[pcap_data->count].info = info;
241 * request printer list from cups, send result back to up parent via fd.
242 * returns true if the (possibly failed) result was successfuly sent to parent.
244 static bool cups_cache_reload_async(int fd)
246 TALLOC_CTX *frame = talloc_stackframe();
247 struct pcap_data pcap_data;
248 http_t *http = NULL; /* HTTP connection to server */
249 ipp_t *request = NULL, /* IPP Request */
250 *response = NULL; /* IPP Response */
251 cups_lang_t *language = NULL; /* Default language */
252 static const char *requested[] =/* Requested attributes */
258 enum ndr_err_code ndr_ret;
261 ZERO_STRUCT(pcap_data);
262 pcap_data.status = NT_STATUS_UNSUCCESSFUL;
264 DEBUG(5, ("reloading cups printcap cache\n"));
267 * Make sure we don't ask for passwords...
270 cupsSetPasswordCB(cups_passwd_cb);
272 if ((http = cups_connect(frame)) == NULL) {
277 * Build a CUPS_GET_PRINTERS request, which requires the following
281 * attributes-natural-language
282 * requested-attributes
287 request->request.op.operation_id = CUPS_GET_PRINTERS;
288 request->request.op.request_id = 1;
290 language = cupsLangDefault();
292 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
293 "attributes-charset", NULL, "utf-8");
295 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
296 "attributes-natural-language", NULL, language->language);
298 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
299 "requested-attributes",
300 (sizeof(requested) / sizeof(requested[0])),
303 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
304 DEBUG(0,("Unable to get printer list - %s\n",
305 ippErrorString(cupsLastError())));
309 ret = process_cups_printers_response(frame, response, &pcap_data);
311 DEBUG(0,("failed to process cups response\n"));
319 * Build a CUPS_GET_CLASSES request, which requires the following
323 * attributes-natural-language
324 * requested-attributes
329 request->request.op.operation_id = CUPS_GET_CLASSES;
330 request->request.op.request_id = 1;
332 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
333 "attributes-charset", NULL, "utf-8");
335 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
336 "attributes-natural-language", NULL, language->language);
338 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
339 "requested-attributes",
340 (sizeof(requested) / sizeof(requested[0])),
343 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
344 DEBUG(0,("Unable to get printer list - %s\n",
345 ippErrorString(cupsLastError())));
349 ret = process_cups_printers_response(frame, response, &pcap_data);
351 DEBUG(0,("failed to process cups response\n"));
355 pcap_data.status = NT_STATUS_OK;
361 cupsLangFree(language);
367 ndr_ret = ndr_push_struct_blob(&pcap_blob, frame, &pcap_data,
368 (ndr_push_flags_fn_t)ndr_push_pcap_data);
369 if (ndr_ret == NDR_ERR_SUCCESS) {
370 ret = send_pcap_blob(&pcap_blob, fd);
377 static struct fd_event *cache_fd_event;
379 static bool cups_pcap_load_async(struct tevent_context *ev,
380 struct messaging_context *msg_ctx,
389 if (cache_fd_event) {
390 DEBUG(3,("cups_pcap_load_async: already waiting for "
391 "a refresh event\n" ));
395 DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n"));
397 if (pipe(fds) == -1) {
402 if (pid == (pid_t)-1) {
403 DEBUG(10,("cups_pcap_load_async: fork failed %s\n",
411 DEBUG(10,("cups_pcap_load_async: child pid = %u\n",
412 (unsigned int)pid ));
421 close_all_print_db();
423 status = reinit_after_fork(msg_ctx, ev, procid_self(), true);
424 if (!NT_STATUS_IS_OK(status)) {
425 DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
426 smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
430 cups_cache_reload_async(fds[1]);
435 struct cups_async_cb_args {
437 struct event_context *event_ctx;
438 struct messaging_context *msg_ctx;
439 void (*post_cache_fill_fn)(struct event_context *,
440 struct messaging_context *);
443 static void cups_async_callback(struct event_context *event_ctx,
444 struct fd_event *event,
448 TALLOC_CTX *frame = talloc_stackframe();
449 struct cups_async_cb_args *cb_args = (struct cups_async_cb_args *)p;
450 struct pcap_cache *tmp_pcap_cache = NULL;
452 struct pcap_data pcap_data;
454 enum ndr_err_code ndr_ret;
457 DEBUG(5,("cups_async_callback: callback received for printer data. "
458 "fd = %d\n", cb_args->pipe_fd));
460 ret_ok = recv_pcap_blob(frame, cb_args->pipe_fd, &pcap_blob);
462 DEBUG(0,("failed to recv pcap blob\n"));
466 ndr_ret = ndr_pull_struct_blob(&pcap_blob, frame, &pcap_data,
467 (ndr_pull_flags_fn_t)ndr_pull_pcap_data);
468 if (ndr_ret != NDR_ERR_SUCCESS) {
472 if (!NT_STATUS_IS_OK(pcap_data.status)) {
473 DEBUG(0,("failed to retrieve printer list: %s\n",
474 nt_errstr(pcap_data.status)));
478 for (i = 0; i < pcap_data.count; i++) {
479 ret_ok = pcap_cache_add_specific(&tmp_pcap_cache,
480 pcap_data.printers[i].name,
481 pcap_data.printers[i].info);
483 DEBUG(0, ("failed to add to tmp pcap cache\n"));
488 /* replace the system-wide pcap cache with a (possibly empty) new one */
489 ret_ok = pcap_cache_replace(tmp_pcap_cache);
491 DEBUG(0, ("failed to replace pcap cache\n"));
492 } else if (cb_args->post_cache_fill_fn != NULL) {
493 /* Caller requested post cache fill callback */
494 cb_args->post_cache_fill_fn(cb_args->event_ctx,
498 pcap_cache_destroy_specific(&tmp_pcap_cache);
500 close(cb_args->pipe_fd);
501 TALLOC_FREE(cb_args);
502 TALLOC_FREE(cache_fd_event);
505 bool cups_cache_reload(struct tevent_context *ev,
506 struct messaging_context *msg_ctx,
507 void (*post_cache_fill_fn)(struct tevent_context *,
508 struct messaging_context *))
510 struct cups_async_cb_args *cb_args;
513 cb_args = TALLOC_P(NULL, struct cups_async_cb_args);
514 if (cb_args == NULL) {
518 cb_args->post_cache_fill_fn = post_cache_fill_fn;
519 cb_args->event_ctx = ev;
520 cb_args->msg_ctx = msg_ctx;
521 p_pipe_fd = &cb_args->pipe_fd;
524 /* Set up an async refresh. */
525 if (!cups_pcap_load_async(ev, msg_ctx, p_pipe_fd)) {
526 talloc_free(cb_args);
530 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
533 /* Trigger an event when the pipe can be read. */
534 cache_fd_event = event_add_fd(ev,
539 if (!cache_fd_event) {
541 TALLOC_FREE(cb_args);
549 * 'cups_job_delete()' - Delete a job.
552 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
554 TALLOC_CTX *frame = talloc_stackframe();
555 int ret = 1; /* Return value */
556 http_t *http = NULL; /* HTTP connection to server */
557 ipp_t *request = NULL, /* IPP Request */
558 *response = NULL; /* IPP Response */
559 cups_lang_t *language = NULL; /* Default language */
561 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
564 DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
567 * Make sure we don't ask for passwords...
570 cupsSetPasswordCB(cups_passwd_cb);
573 * Try to connect to the server...
576 if ((http = cups_connect(frame)) == NULL) {
581 * Build an IPP_CANCEL_JOB request, which requires the following
585 * attributes-natural-language
587 * requesting-user-name
592 request->request.op.operation_id = IPP_CANCEL_JOB;
593 request->request.op.request_id = 1;
595 language = cupsLangDefault();
597 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
598 "attributes-charset", NULL, "utf-8");
600 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
601 "attributes-natural-language", NULL, language->language);
603 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
605 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
607 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
611 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
615 * Do the request and get back a response...
618 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
619 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
620 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
621 ippErrorString(cupsLastError())));
626 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
627 ippErrorString(cupsLastError())));
635 cupsLangFree(language);
646 * 'cups_job_pause()' - Pause a job.
649 static int cups_job_pause(int snum, struct printjob *pjob)
651 TALLOC_CTX *frame = talloc_stackframe();
652 int ret = 1; /* Return value */
653 http_t *http = NULL; /* HTTP connection to server */
654 ipp_t *request = NULL, /* IPP Request */
655 *response = NULL; /* IPP Response */
656 cups_lang_t *language = NULL; /* Default language */
658 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
661 DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
664 * Make sure we don't ask for passwords...
667 cupsSetPasswordCB(cups_passwd_cb);
670 * Try to connect to the server...
673 if ((http = cups_connect(frame)) == NULL) {
678 * Build an IPP_HOLD_JOB request, which requires the following
682 * attributes-natural-language
684 * requesting-user-name
689 request->request.op.operation_id = IPP_HOLD_JOB;
690 request->request.op.request_id = 1;
692 language = cupsLangDefault();
694 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
695 "attributes-charset", NULL, "utf-8");
697 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
698 "attributes-natural-language", NULL, language->language);
700 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
702 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
704 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
707 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
711 * Do the request and get back a response...
714 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
715 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
716 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
717 ippErrorString(cupsLastError())));
722 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
723 ippErrorString(cupsLastError())));
731 cupsLangFree(language);
742 * 'cups_job_resume()' - Resume a paused job.
745 static int cups_job_resume(int snum, struct printjob *pjob)
747 TALLOC_CTX *frame = talloc_stackframe();
748 int ret = 1; /* Return value */
749 http_t *http = NULL; /* HTTP connection to server */
750 ipp_t *request = NULL, /* IPP Request */
751 *response = NULL; /* IPP Response */
752 cups_lang_t *language = NULL; /* Default language */
754 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
757 DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
760 * Make sure we don't ask for passwords...
763 cupsSetPasswordCB(cups_passwd_cb);
766 * Try to connect to the server...
769 if ((http = cups_connect(frame)) == NULL) {
774 * Build an IPP_RELEASE_JOB request, which requires the following
778 * attributes-natural-language
780 * requesting-user-name
785 request->request.op.operation_id = IPP_RELEASE_JOB;
786 request->request.op.request_id = 1;
788 language = cupsLangDefault();
790 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
791 "attributes-charset", NULL, "utf-8");
793 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
794 "attributes-natural-language", NULL, language->language);
796 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
798 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
800 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
803 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
807 * Do the request and get back a response...
810 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
811 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
812 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
813 ippErrorString(cupsLastError())));
818 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
819 ippErrorString(cupsLastError())));
827 cupsLangFree(language);
838 * 'cups_job_submit()' - Submit a job for printing.
841 static int cups_job_submit(int snum, struct printjob *pjob)
843 TALLOC_CTX *frame = talloc_stackframe();
844 int ret = 1; /* Return value */
845 http_t *http = NULL; /* HTTP connection to server */
846 ipp_t *request = NULL, /* IPP Request */
847 *response = NULL; /* IPP Response */
848 ipp_attribute_t *attr_job_id = NULL; /* IPP Attribute "job-id" */
849 cups_lang_t *language = NULL; /* Default language */
850 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
851 char *new_jobname = NULL;
853 cups_option_t *options = NULL;
854 char *printername = NULL;
856 char *jobname = NULL;
857 char *cupsoptions = NULL;
858 char *filename = NULL;
860 uint32_t jobid = (uint32_t)-1;
862 DEBUG(5,("cups_job_submit(%d, %p)\n", snum, pjob));
865 * Make sure we don't ask for passwords...
868 cupsSetPasswordCB(cups_passwd_cb);
871 * Try to connect to the server...
874 if ((http = cups_connect(frame)) == NULL) {
879 * Build an IPP_PRINT_JOB request, which requires the following
883 * attributes-natural-language
885 * requesting-user-name
891 request->request.op.operation_id = IPP_PRINT_JOB;
892 request->request.op.request_id = 1;
894 language = cupsLangDefault();
896 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
897 "attributes-charset", NULL, "utf-8");
899 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
900 "attributes-natural-language", NULL, language->language);
902 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
906 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
909 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
910 "printer-uri", NULL, uri);
912 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
915 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
918 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
919 "job-originating-host-name", NULL,
920 pjob->clientmachine);
922 /* Get the jobid from the filename. */
923 jobid = print_parse_jobid(pjob->filename);
924 if (jobid == (uint32_t)-1) {
925 DEBUG(0,("cups_job_submit: failed to parse jobid from name %s\n",
930 if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
933 new_jobname = talloc_asprintf(frame,
934 "%s%.8u %s", PRINT_SPOOL_PREFIX,
937 if (new_jobname == NULL) {
941 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
945 * add any options defined in smb.conf
948 if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
953 num_options = cupsParseOptions(cupsoptions, num_options, &options);
956 cupsEncodeOptions(request, num_options, options);
959 * Do the request and get back a response...
962 slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
964 if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
967 if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
968 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
969 DEBUG(0,("Unable to print file to %s - %s\n",
970 lp_printername(snum),
971 ippErrorString(cupsLastError())));
974 attr_job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
976 pjob->sysjob = attr_job_id->values[0].integer;
977 DEBUG(5,("cups_job_submit: job-id %d\n", pjob->sysjob));
979 DEBUG(0,("Missing job-id attribute in IPP response"));
983 DEBUG(0,("Unable to print file to `%s' - %s\n",
984 lp_printername(snum),
985 ippErrorString(cupsLastError())));
989 unlink(pjob->filename);
990 /* else print_job_end will do it for us */
997 cupsLangFree(language);
1008 * 'cups_queue_get()' - Get all the jobs in the print queue.
1011 static int cups_queue_get(const char *sharename,
1012 enum printing_types printing_type,
1014 print_queue_struct **q,
1015 print_status_struct *status)
1017 TALLOC_CTX *frame = talloc_stackframe();
1018 char *printername = NULL;
1019 http_t *http = NULL; /* HTTP connection to server */
1020 ipp_t *request = NULL, /* IPP Request */
1021 *response = NULL; /* IPP Response */
1022 ipp_attribute_t *attr = NULL; /* Current attribute */
1023 cups_lang_t *language = NULL; /* Default language */
1024 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1025 int qcount = 0, /* Number of active queue entries */
1026 qalloc = 0; /* Number of queue entries allocated */
1027 print_queue_struct *queue = NULL, /* Queue entries */
1028 *temp; /* Temporary pointer for queue */
1029 char *user_name = NULL, /* job-originating-user-name attribute */
1030 *job_name = NULL; /* job-name attribute */
1031 int job_id; /* job-id attribute */
1032 int job_k_octets; /* job-k-octets attribute */
1033 time_t job_time; /* time-at-creation attribute */
1034 ipp_jstate_t job_status; /* job-status attribute */
1035 int job_priority; /* job-priority attribute */
1037 static const char *jattrs[] = /* Requested job attributes */
1042 "job-originating-user-name",
1047 static const char *pattrs[] = /* Requested printer attributes */
1050 "printer-state-message"
1055 /* HACK ALERT!!! The problem with support the 'printer name'
1056 option is that we key the tdb off the sharename. So we will
1057 overload the lpq_command string to pass in the printername
1058 (which is basically what we do for non-cups printers ... using
1059 the lpq_command to get the queue listing). */
1061 if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1064 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1067 * Make sure we don't ask for passwords...
1070 cupsSetPasswordCB(cups_passwd_cb);
1073 * Try to connect to the server...
1076 if ((http = cups_connect(frame)) == NULL) {
1081 * Generate the printer URI...
1084 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1087 * Build an IPP_GET_JOBS request, which requires the following
1090 * attributes-charset
1091 * attributes-natural-language
1092 * requested-attributes
1098 request->request.op.operation_id = IPP_GET_JOBS;
1099 request->request.op.request_id = 1;
1101 language = cupsLangDefault();
1103 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1104 "attributes-charset", NULL, "utf-8");
1106 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1107 "attributes-natural-language", NULL, language->language);
1109 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1110 "requested-attributes",
1111 (sizeof(jattrs) / sizeof(jattrs[0])),
1114 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1115 "printer-uri", NULL, uri);
1118 * Do the request and get back a response...
1121 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1122 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1123 ippErrorString(cupsLastError())));
1127 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1128 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1129 ippErrorString(response->request.status.status_code)));
1134 * Process the jobs...
1141 for (attr = response->attrs; attr != NULL; attr = attr->next) {
1143 * Skip leading attributes until we hit a job...
1146 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1153 * Allocate memory as needed...
1155 if (qcount >= qalloc) {
1158 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1160 if (queue == NULL) {
1161 DEBUG(0,("cups_queue_get: Not enough memory!"));
1167 temp = queue + qcount;
1168 memset(temp, 0, sizeof(print_queue_struct));
1171 * Pull the needed attributes from this job...
1176 job_status = IPP_JOB_PENDING;
1182 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1183 if (attr->name == NULL) {
1188 if (strcmp(attr->name, "job-id") == 0 &&
1189 attr->value_tag == IPP_TAG_INTEGER)
1190 job_id = attr->values[0].integer;
1192 if (strcmp(attr->name, "job-k-octets") == 0 &&
1193 attr->value_tag == IPP_TAG_INTEGER)
1194 job_k_octets = attr->values[0].integer;
1196 if (strcmp(attr->name, "job-priority") == 0 &&
1197 attr->value_tag == IPP_TAG_INTEGER)
1198 job_priority = attr->values[0].integer;
1200 if (strcmp(attr->name, "job-state") == 0 &&
1201 attr->value_tag == IPP_TAG_ENUM)
1202 job_status = (ipp_jstate_t)(attr->values[0].integer);
1204 if (strcmp(attr->name, "time-at-creation") == 0 &&
1205 attr->value_tag == IPP_TAG_INTEGER)
1206 job_time = attr->values[0].integer;
1208 if (strcmp(attr->name, "job-name") == 0 &&
1209 attr->value_tag == IPP_TAG_NAME) {
1210 if (!pull_utf8_talloc(frame,
1212 attr->values[0].string.text,
1218 if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1219 attr->value_tag == IPP_TAG_NAME) {
1220 if (!pull_utf8_talloc(frame,
1222 attr->values[0].string.text,
1232 * See if we have everything needed...
1235 if (user_name == NULL || job_name == NULL || job_id == 0) {
1243 temp->size = job_k_octets * 1024;
1244 temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1245 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1246 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1248 temp->priority = job_priority;
1249 temp->time = job_time;
1250 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1251 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1259 ippDelete(response);
1263 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1264 * following attributes:
1266 * attributes-charset
1267 * attributes-natural-language
1268 * requested-attributes
1274 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1275 request->request.op.request_id = 1;
1277 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1278 "attributes-charset", NULL, "utf-8");
1280 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1281 "attributes-natural-language", NULL, language->language);
1283 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1284 "requested-attributes",
1285 (sizeof(pattrs) / sizeof(pattrs[0])),
1288 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1289 "printer-uri", NULL, uri);
1292 * Do the request and get back a response...
1295 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1296 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1297 ippErrorString(cupsLastError())));
1301 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1302 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1303 ippErrorString(response->request.status.status_code)));
1308 * Get the current printer status and convert it to the SAMBA values.
1311 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1312 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1313 status->status = LPSTAT_STOPPED;
1315 status->status = LPSTAT_OK;
1318 if ((attr = ippFindAttribute(response, "printer-state-message",
1319 IPP_TAG_TEXT)) != NULL) {
1321 if (!pull_utf8_talloc(frame, &msg,
1322 attr->values[0].string.text,
1328 fstrcpy(status->message, msg);
1334 * Return the job queue...
1340 ippDelete(response);
1343 cupsLangFree(language);
1354 * 'cups_queue_pause()' - Pause a print queue.
1357 static int cups_queue_pause(int snum)
1359 TALLOC_CTX *frame = talloc_stackframe();
1360 int ret = 1; /* Return value */
1361 http_t *http = NULL; /* HTTP connection to server */
1362 ipp_t *request = NULL, /* IPP Request */
1363 *response = NULL; /* IPP Response */
1364 cups_lang_t *language = NULL; /* Default language */
1365 char *printername = NULL;
1366 char *username = NULL;
1367 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1370 DEBUG(5,("cups_queue_pause(%d)\n", snum));
1373 * Make sure we don't ask for passwords...
1376 cupsSetPasswordCB(cups_passwd_cb);
1379 * Try to connect to the server...
1382 if ((http = cups_connect(frame)) == NULL) {
1387 * Build an IPP_PAUSE_PRINTER request, which requires the following
1390 * attributes-charset
1391 * attributes-natural-language
1393 * requesting-user-name
1398 request->request.op.operation_id = IPP_PAUSE_PRINTER;
1399 request->request.op.request_id = 1;
1401 language = cupsLangDefault();
1403 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1404 "attributes-charset", NULL, "utf-8");
1406 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1407 "attributes-natural-language", NULL, language->language);
1409 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1413 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1416 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1418 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1421 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1425 * Do the request and get back a response...
1428 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1429 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1430 DEBUG(0,("Unable to pause printer %s - %s\n",
1431 lp_printername(snum),
1432 ippErrorString(cupsLastError())));
1437 DEBUG(0,("Unable to pause printer %s - %s\n",
1438 lp_printername(snum),
1439 ippErrorString(cupsLastError())));
1444 ippDelete(response);
1447 cupsLangFree(language);
1458 * 'cups_queue_resume()' - Restart a print queue.
1461 static int cups_queue_resume(int snum)
1463 TALLOC_CTX *frame = talloc_stackframe();
1464 int ret = 1; /* Return value */
1465 http_t *http = NULL; /* HTTP connection to server */
1466 ipp_t *request = NULL, /* IPP Request */
1467 *response = NULL; /* IPP Response */
1468 cups_lang_t *language = NULL; /* Default language */
1469 char *printername = NULL;
1470 char *username = NULL;
1471 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1474 DEBUG(5,("cups_queue_resume(%d)\n", snum));
1477 * Make sure we don't ask for passwords...
1480 cupsSetPasswordCB(cups_passwd_cb);
1483 * Try to connect to the server...
1486 if ((http = cups_connect(frame)) == NULL) {
1491 * Build an IPP_RESUME_PRINTER request, which requires the following
1494 * attributes-charset
1495 * attributes-natural-language
1497 * requesting-user-name
1502 request->request.op.operation_id = IPP_RESUME_PRINTER;
1503 request->request.op.request_id = 1;
1505 language = cupsLangDefault();
1507 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1508 "attributes-charset", NULL, "utf-8");
1510 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1511 "attributes-natural-language", NULL, language->language);
1513 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1517 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1520 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1522 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1525 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1529 * Do the request and get back a response...
1532 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1533 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1534 DEBUG(0,("Unable to resume printer %s - %s\n",
1535 lp_printername(snum),
1536 ippErrorString(cupsLastError())));
1541 DEBUG(0,("Unable to resume printer %s - %s\n",
1542 lp_printername(snum),
1543 ippErrorString(cupsLastError())));
1548 ippDelete(response);
1551 cupsLangFree(language);
1560 /*******************************************************************
1561 * CUPS printing interface definitions...
1562 ******************************************************************/
1564 struct printif cups_printif =
1576 bool cups_pull_comment_location(TALLOC_CTX *mem_ctx,
1577 const char *printername,
1581 TALLOC_CTX *frame = talloc_stackframe();
1582 http_t *http = NULL; /* HTTP connection to server */
1583 ipp_t *request = NULL, /* IPP Request */
1584 *response = NULL; /* IPP Response */
1585 ipp_attribute_t *attr; /* Current attribute */
1586 cups_lang_t *language = NULL; /* Default language */
1587 char uri[HTTP_MAX_URI];
1588 char *server = NULL;
1589 char *sharename = NULL;
1591 static const char *requested[] =/* Requested attributes */
1600 DEBUG(5, ("pulling %s location\n", printername));
1603 * Make sure we don't ask for passwords...
1606 cupsSetPasswordCB(cups_passwd_cb);
1609 * Try to connect to the server...
1612 if ((http = cups_connect(frame)) == NULL) {
1618 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1619 request->request.op.request_id = 1;
1621 language = cupsLangDefault();
1623 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1624 "attributes-charset", NULL, "utf-8");
1626 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1627 "attributes-natural-language", NULL, language->language);
1629 if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1630 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
1634 server = talloc_strdup(frame,cupsServer());
1639 if (!push_utf8_talloc(frame, &sharename, printername, &size)) {
1642 slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1645 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1646 "printer-uri", NULL, uri);
1648 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1649 "requested-attributes",
1650 (sizeof(requested) / sizeof(requested[0])),
1654 * Do the request and get back a response...
1657 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1658 DEBUG(0,("Unable to get printer attributes - %s\n",
1659 ippErrorString(cupsLastError())));
1663 for (attr = response->attrs; attr != NULL;) {
1665 * Skip leading attributes until we hit a printer...
1668 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1675 * Pull the needed attributes from this printer...
1678 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1679 if (strcmp(attr->name, "printer-name") == 0 &&
1680 attr->value_tag == IPP_TAG_NAME) {
1681 if (!pull_utf8_talloc(frame,
1683 attr->values[0].string.text,
1689 /* Grab the comment if we don't have one */
1690 if ( (strcmp(attr->name, "printer-info") == 0)
1691 && (attr->value_tag == IPP_TAG_TEXT))
1693 if (!pull_utf8_talloc(mem_ctx,
1695 attr->values[0].string.text,
1699 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1703 /* Grab the location if we don't have one */
1704 if ( (strcmp(attr->name, "printer-location") == 0)
1705 && (attr->value_tag == IPP_TAG_TEXT))
1707 if (!pull_utf8_talloc(mem_ctx,
1709 attr->values[0].string.text,
1713 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1721 * We have everything needed...
1732 ippDelete(response);
1739 cupsLangFree(language);
1749 /* this keeps fussy compilers happy */
1750 void print_cups_dummy(void);
1751 void print_cups_dummy(void) {}
1752 #endif /* HAVE_CUPS */