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 %ld\n", (int64_t)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 %ld\n", (int64_t)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"));
489 DEBUG(0, ("failed to read a new printer list\n"));
490 pcap_cache_destroy_specific(&tmp_pcap_cache);
493 * replace the system-wide pcap cache with a (possibly empty)
496 ret_ok = pcap_cache_replace(tmp_pcap_cache);
498 DEBUG(0, ("failed to replace pcap cache\n"));
499 } else if (cb_args->post_cache_fill_fn != NULL) {
500 /* Caller requested post cache fill callback */
501 cb_args->post_cache_fill_fn(cb_args->event_ctx,
507 close(cb_args->pipe_fd);
508 TALLOC_FREE(cb_args);
509 TALLOC_FREE(cache_fd_event);
512 bool cups_cache_reload(struct tevent_context *ev,
513 struct messaging_context *msg_ctx,
514 void (*post_cache_fill_fn)(struct tevent_context *,
515 struct messaging_context *))
517 struct cups_async_cb_args *cb_args;
520 cb_args = TALLOC_P(NULL, struct cups_async_cb_args);
521 if (cb_args == NULL) {
525 cb_args->post_cache_fill_fn = post_cache_fill_fn;
526 cb_args->event_ctx = ev;
527 cb_args->msg_ctx = msg_ctx;
528 p_pipe_fd = &cb_args->pipe_fd;
531 /* Set up an async refresh. */
532 if (!cups_pcap_load_async(ev, msg_ctx, p_pipe_fd)) {
533 talloc_free(cb_args);
537 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
540 /* Trigger an event when the pipe can be read. */
541 cache_fd_event = event_add_fd(ev,
546 if (!cache_fd_event) {
548 TALLOC_FREE(cb_args);
556 * 'cups_job_delete()' - Delete a job.
559 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
561 TALLOC_CTX *frame = talloc_stackframe();
562 int ret = 1; /* Return value */
563 http_t *http = NULL; /* HTTP connection to server */
564 ipp_t *request = NULL, /* IPP Request */
565 *response = NULL; /* IPP Response */
566 cups_lang_t *language = NULL; /* Default language */
568 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
571 DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
574 * Make sure we don't ask for passwords...
577 cupsSetPasswordCB(cups_passwd_cb);
580 * Try to connect to the server...
583 if ((http = cups_connect(frame)) == NULL) {
588 * Build an IPP_CANCEL_JOB request, which requires the following
592 * attributes-natural-language
594 * requesting-user-name
599 request->request.op.operation_id = IPP_CANCEL_JOB;
600 request->request.op.request_id = 1;
602 language = cupsLangDefault();
604 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
605 "attributes-charset", NULL, "utf-8");
607 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
608 "attributes-natural-language", NULL, language->language);
610 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
612 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
614 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
618 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
622 * Do the request and get back a response...
625 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
626 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
627 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
628 ippErrorString(cupsLastError())));
633 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
634 ippErrorString(cupsLastError())));
642 cupsLangFree(language);
653 * 'cups_job_pause()' - Pause a job.
656 static int cups_job_pause(int snum, struct printjob *pjob)
658 TALLOC_CTX *frame = talloc_stackframe();
659 int ret = 1; /* Return value */
660 http_t *http = NULL; /* HTTP connection to server */
661 ipp_t *request = NULL, /* IPP Request */
662 *response = NULL; /* IPP Response */
663 cups_lang_t *language = NULL; /* Default language */
665 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
668 DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
671 * Make sure we don't ask for passwords...
674 cupsSetPasswordCB(cups_passwd_cb);
677 * Try to connect to the server...
680 if ((http = cups_connect(frame)) == NULL) {
685 * Build an IPP_HOLD_JOB request, which requires the following
689 * attributes-natural-language
691 * requesting-user-name
696 request->request.op.operation_id = IPP_HOLD_JOB;
697 request->request.op.request_id = 1;
699 language = cupsLangDefault();
701 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
702 "attributes-charset", NULL, "utf-8");
704 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
705 "attributes-natural-language", NULL, language->language);
707 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
709 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
711 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
714 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
718 * Do the request and get back a response...
721 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
722 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
723 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
724 ippErrorString(cupsLastError())));
729 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
730 ippErrorString(cupsLastError())));
738 cupsLangFree(language);
749 * 'cups_job_resume()' - Resume a paused job.
752 static int cups_job_resume(int snum, struct printjob *pjob)
754 TALLOC_CTX *frame = talloc_stackframe();
755 int ret = 1; /* Return value */
756 http_t *http = NULL; /* HTTP connection to server */
757 ipp_t *request = NULL, /* IPP Request */
758 *response = NULL; /* IPP Response */
759 cups_lang_t *language = NULL; /* Default language */
761 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
764 DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
767 * Make sure we don't ask for passwords...
770 cupsSetPasswordCB(cups_passwd_cb);
773 * Try to connect to the server...
776 if ((http = cups_connect(frame)) == NULL) {
781 * Build an IPP_RELEASE_JOB request, which requires the following
785 * attributes-natural-language
787 * requesting-user-name
792 request->request.op.operation_id = IPP_RELEASE_JOB;
793 request->request.op.request_id = 1;
795 language = cupsLangDefault();
797 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
798 "attributes-charset", NULL, "utf-8");
800 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
801 "attributes-natural-language", NULL, language->language);
803 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
805 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
807 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
810 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
814 * Do the request and get back a response...
817 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
818 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
819 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
820 ippErrorString(cupsLastError())));
825 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
826 ippErrorString(cupsLastError())));
834 cupsLangFree(language);
845 * 'cups_job_submit()' - Submit a job for printing.
848 static int cups_job_submit(int snum, struct printjob *pjob)
850 TALLOC_CTX *frame = talloc_stackframe();
851 int ret = 1; /* Return value */
852 http_t *http = NULL; /* HTTP connection to server */
853 ipp_t *request = NULL, /* IPP Request */
854 *response = NULL; /* IPP Response */
855 ipp_attribute_t *attr_job_id = NULL; /* IPP Attribute "job-id" */
856 cups_lang_t *language = NULL; /* Default language */
857 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
858 char *new_jobname = NULL;
860 cups_option_t *options = NULL;
861 char *printername = NULL;
863 char *jobname = NULL;
864 char *cupsoptions = NULL;
865 char *filename = NULL;
867 uint32_t jobid = (uint32_t)-1;
869 DEBUG(5,("cups_job_submit(%d, %p)\n", snum, pjob));
872 * Make sure we don't ask for passwords...
875 cupsSetPasswordCB(cups_passwd_cb);
878 * Try to connect to the server...
881 if ((http = cups_connect(frame)) == NULL) {
886 * Build an IPP_PRINT_JOB request, which requires the following
890 * attributes-natural-language
892 * requesting-user-name
898 request->request.op.operation_id = IPP_PRINT_JOB;
899 request->request.op.request_id = 1;
901 language = cupsLangDefault();
903 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
904 "attributes-charset", NULL, "utf-8");
906 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
907 "attributes-natural-language", NULL, language->language);
909 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
913 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
916 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
917 "printer-uri", NULL, uri);
919 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
922 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
925 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
926 "job-originating-host-name", NULL,
927 pjob->clientmachine);
929 /* Get the jobid from the filename. */
930 jobid = print_parse_jobid(pjob->filename);
931 if (jobid == (uint32_t)-1) {
932 DEBUG(0,("cups_job_submit: failed to parse jobid from name %s\n",
937 if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
940 new_jobname = talloc_asprintf(frame,
941 "%s%.8u %s", PRINT_SPOOL_PREFIX,
944 if (new_jobname == NULL) {
948 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
952 * add any options defined in smb.conf
955 if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
960 num_options = cupsParseOptions(cupsoptions, num_options, &options);
963 cupsEncodeOptions(request, num_options, options);
966 * Do the request and get back a response...
969 slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
971 if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
974 if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
975 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
976 DEBUG(0,("Unable to print file to %s - %s\n",
977 lp_printername(snum),
978 ippErrorString(cupsLastError())));
981 attr_job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
983 pjob->sysjob = attr_job_id->values[0].integer;
984 DEBUG(5,("cups_job_submit: job-id %d\n", pjob->sysjob));
986 DEBUG(0,("Missing job-id attribute in IPP response"));
990 DEBUG(0,("Unable to print file to `%s' - %s\n",
991 lp_printername(snum),
992 ippErrorString(cupsLastError())));
996 unlink(pjob->filename);
997 /* else print_job_end will do it for us */
1001 ippDelete(response);
1004 cupsLangFree(language);
1015 * 'cups_queue_get()' - Get all the jobs in the print queue.
1018 static int cups_queue_get(const char *sharename,
1019 enum printing_types printing_type,
1021 print_queue_struct **q,
1022 print_status_struct *status)
1024 TALLOC_CTX *frame = talloc_stackframe();
1025 char *printername = NULL;
1026 http_t *http = NULL; /* HTTP connection to server */
1027 ipp_t *request = NULL, /* IPP Request */
1028 *response = NULL; /* IPP Response */
1029 ipp_attribute_t *attr = NULL; /* Current attribute */
1030 cups_lang_t *language = NULL; /* Default language */
1031 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1032 int qcount = 0, /* Number of active queue entries */
1033 qalloc = 0; /* Number of queue entries allocated */
1034 print_queue_struct *queue = NULL, /* Queue entries */
1035 *temp; /* Temporary pointer for queue */
1036 char *user_name = NULL, /* job-originating-user-name attribute */
1037 *job_name = NULL; /* job-name attribute */
1038 int job_id; /* job-id attribute */
1039 int job_k_octets; /* job-k-octets attribute */
1040 time_t job_time; /* time-at-creation attribute */
1041 ipp_jstate_t job_status; /* job-status attribute */
1042 int job_priority; /* job-priority attribute */
1044 static const char *jattrs[] = /* Requested job attributes */
1049 "job-originating-user-name",
1054 static const char *pattrs[] = /* Requested printer attributes */
1057 "printer-state-message"
1062 /* HACK ALERT!!! The problem with support the 'printer name'
1063 option is that we key the tdb off the sharename. So we will
1064 overload the lpq_command string to pass in the printername
1065 (which is basically what we do for non-cups printers ... using
1066 the lpq_command to get the queue listing). */
1068 if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1071 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1074 * Make sure we don't ask for passwords...
1077 cupsSetPasswordCB(cups_passwd_cb);
1080 * Try to connect to the server...
1083 if ((http = cups_connect(frame)) == NULL) {
1088 * Generate the printer URI...
1091 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1094 * Build an IPP_GET_JOBS request, which requires the following
1097 * attributes-charset
1098 * attributes-natural-language
1099 * requested-attributes
1105 request->request.op.operation_id = IPP_GET_JOBS;
1106 request->request.op.request_id = 1;
1108 language = cupsLangDefault();
1110 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1111 "attributes-charset", NULL, "utf-8");
1113 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1114 "attributes-natural-language", NULL, language->language);
1116 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1117 "requested-attributes",
1118 (sizeof(jattrs) / sizeof(jattrs[0])),
1121 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1122 "printer-uri", NULL, uri);
1125 * Do the request and get back a response...
1128 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1129 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1130 ippErrorString(cupsLastError())));
1134 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1135 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1136 ippErrorString(response->request.status.status_code)));
1141 * Process the jobs...
1148 for (attr = response->attrs; attr != NULL; attr = attr->next) {
1150 * Skip leading attributes until we hit a job...
1153 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1160 * Allocate memory as needed...
1162 if (qcount >= qalloc) {
1165 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1167 if (queue == NULL) {
1168 DEBUG(0,("cups_queue_get: Not enough memory!"));
1174 temp = queue + qcount;
1175 memset(temp, 0, sizeof(print_queue_struct));
1178 * Pull the needed attributes from this job...
1183 job_status = IPP_JOB_PENDING;
1189 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1190 if (attr->name == NULL) {
1195 if (strcmp(attr->name, "job-id") == 0 &&
1196 attr->value_tag == IPP_TAG_INTEGER)
1197 job_id = attr->values[0].integer;
1199 if (strcmp(attr->name, "job-k-octets") == 0 &&
1200 attr->value_tag == IPP_TAG_INTEGER)
1201 job_k_octets = attr->values[0].integer;
1203 if (strcmp(attr->name, "job-priority") == 0 &&
1204 attr->value_tag == IPP_TAG_INTEGER)
1205 job_priority = attr->values[0].integer;
1207 if (strcmp(attr->name, "job-state") == 0 &&
1208 attr->value_tag == IPP_TAG_ENUM)
1209 job_status = (ipp_jstate_t)(attr->values[0].integer);
1211 if (strcmp(attr->name, "time-at-creation") == 0 &&
1212 attr->value_tag == IPP_TAG_INTEGER)
1213 job_time = attr->values[0].integer;
1215 if (strcmp(attr->name, "job-name") == 0 &&
1216 attr->value_tag == IPP_TAG_NAME) {
1217 if (!pull_utf8_talloc(frame,
1219 attr->values[0].string.text,
1225 if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1226 attr->value_tag == IPP_TAG_NAME) {
1227 if (!pull_utf8_talloc(frame,
1229 attr->values[0].string.text,
1239 * See if we have everything needed...
1242 if (user_name == NULL || job_name == NULL || job_id == 0) {
1250 temp->size = job_k_octets * 1024;
1251 temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1252 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1253 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1255 temp->priority = job_priority;
1256 temp->time = job_time;
1257 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1258 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1266 ippDelete(response);
1270 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1271 * following attributes:
1273 * attributes-charset
1274 * attributes-natural-language
1275 * requested-attributes
1281 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1282 request->request.op.request_id = 1;
1284 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1285 "attributes-charset", NULL, "utf-8");
1287 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1288 "attributes-natural-language", NULL, language->language);
1290 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1291 "requested-attributes",
1292 (sizeof(pattrs) / sizeof(pattrs[0])),
1295 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1296 "printer-uri", NULL, uri);
1299 * Do the request and get back a response...
1302 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1303 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1304 ippErrorString(cupsLastError())));
1308 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1309 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1310 ippErrorString(response->request.status.status_code)));
1315 * Get the current printer status and convert it to the SAMBA values.
1318 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1319 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1320 status->status = LPSTAT_STOPPED;
1322 status->status = LPSTAT_OK;
1325 if ((attr = ippFindAttribute(response, "printer-state-message",
1326 IPP_TAG_TEXT)) != NULL) {
1328 if (!pull_utf8_talloc(frame, &msg,
1329 attr->values[0].string.text,
1335 fstrcpy(status->message, msg);
1341 * Return the job queue...
1347 ippDelete(response);
1350 cupsLangFree(language);
1361 * 'cups_queue_pause()' - Pause a print queue.
1364 static int cups_queue_pause(int snum)
1366 TALLOC_CTX *frame = talloc_stackframe();
1367 int ret = 1; /* Return value */
1368 http_t *http = NULL; /* HTTP connection to server */
1369 ipp_t *request = NULL, /* IPP Request */
1370 *response = NULL; /* IPP Response */
1371 cups_lang_t *language = NULL; /* Default language */
1372 char *printername = NULL;
1373 char *username = NULL;
1374 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1377 DEBUG(5,("cups_queue_pause(%d)\n", snum));
1380 * Make sure we don't ask for passwords...
1383 cupsSetPasswordCB(cups_passwd_cb);
1386 * Try to connect to the server...
1389 if ((http = cups_connect(frame)) == NULL) {
1394 * Build an IPP_PAUSE_PRINTER request, which requires the following
1397 * attributes-charset
1398 * attributes-natural-language
1400 * requesting-user-name
1405 request->request.op.operation_id = IPP_PAUSE_PRINTER;
1406 request->request.op.request_id = 1;
1408 language = cupsLangDefault();
1410 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1411 "attributes-charset", NULL, "utf-8");
1413 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1414 "attributes-natural-language", NULL, language->language);
1416 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1420 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1423 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1425 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1428 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1432 * Do the request and get back a response...
1435 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1436 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1437 DEBUG(0,("Unable to pause printer %s - %s\n",
1438 lp_printername(snum),
1439 ippErrorString(cupsLastError())));
1444 DEBUG(0,("Unable to pause printer %s - %s\n",
1445 lp_printername(snum),
1446 ippErrorString(cupsLastError())));
1451 ippDelete(response);
1454 cupsLangFree(language);
1465 * 'cups_queue_resume()' - Restart a print queue.
1468 static int cups_queue_resume(int snum)
1470 TALLOC_CTX *frame = talloc_stackframe();
1471 int ret = 1; /* Return value */
1472 http_t *http = NULL; /* HTTP connection to server */
1473 ipp_t *request = NULL, /* IPP Request */
1474 *response = NULL; /* IPP Response */
1475 cups_lang_t *language = NULL; /* Default language */
1476 char *printername = NULL;
1477 char *username = NULL;
1478 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1481 DEBUG(5,("cups_queue_resume(%d)\n", snum));
1484 * Make sure we don't ask for passwords...
1487 cupsSetPasswordCB(cups_passwd_cb);
1490 * Try to connect to the server...
1493 if ((http = cups_connect(frame)) == NULL) {
1498 * Build an IPP_RESUME_PRINTER request, which requires the following
1501 * attributes-charset
1502 * attributes-natural-language
1504 * requesting-user-name
1509 request->request.op.operation_id = IPP_RESUME_PRINTER;
1510 request->request.op.request_id = 1;
1512 language = cupsLangDefault();
1514 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1515 "attributes-charset", NULL, "utf-8");
1517 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1518 "attributes-natural-language", NULL, language->language);
1520 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1524 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1527 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1529 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1532 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1536 * Do the request and get back a response...
1539 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1540 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1541 DEBUG(0,("Unable to resume printer %s - %s\n",
1542 lp_printername(snum),
1543 ippErrorString(cupsLastError())));
1548 DEBUG(0,("Unable to resume printer %s - %s\n",
1549 lp_printername(snum),
1550 ippErrorString(cupsLastError())));
1555 ippDelete(response);
1558 cupsLangFree(language);
1567 /*******************************************************************
1568 * CUPS printing interface definitions...
1569 ******************************************************************/
1571 struct printif cups_printif =
1583 bool cups_pull_comment_location(TALLOC_CTX *mem_ctx,
1584 const char *printername,
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 *server = NULL;
1596 char *sharename = NULL;
1598 static const char *requested[] =/* Requested attributes */
1607 DEBUG(5, ("pulling %s location\n", printername));
1610 * Make sure we don't ask for passwords...
1613 cupsSetPasswordCB(cups_passwd_cb);
1616 * Try to connect to the server...
1619 if ((http = cups_connect(frame)) == NULL) {
1625 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1626 request->request.op.request_id = 1;
1628 language = cupsLangDefault();
1630 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1631 "attributes-charset", NULL, "utf-8");
1633 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1634 "attributes-natural-language", NULL, language->language);
1636 if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1637 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
1641 server = talloc_strdup(frame,cupsServer());
1646 if (!push_utf8_talloc(frame, &sharename, printername, &size)) {
1649 slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1652 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1653 "printer-uri", NULL, uri);
1655 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1656 "requested-attributes",
1657 (sizeof(requested) / sizeof(requested[0])),
1661 * Do the request and get back a response...
1664 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1665 DEBUG(0,("Unable to get printer attributes - %s\n",
1666 ippErrorString(cupsLastError())));
1670 for (attr = response->attrs; attr != NULL;) {
1672 * Skip leading attributes until we hit a printer...
1675 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1682 * Pull the needed attributes from this printer...
1685 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1686 if (strcmp(attr->name, "printer-name") == 0 &&
1687 attr->value_tag == IPP_TAG_NAME) {
1688 if (!pull_utf8_talloc(frame,
1690 attr->values[0].string.text,
1696 /* Grab the comment if we don't have one */
1697 if ( (strcmp(attr->name, "printer-info") == 0)
1698 && (attr->value_tag == IPP_TAG_TEXT))
1700 if (!pull_utf8_talloc(mem_ctx,
1702 attr->values[0].string.text,
1706 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1710 /* Grab the location if we don't have one */
1711 if ( (strcmp(attr->name, "printer-location") == 0)
1712 && (attr->value_tag == IPP_TAG_TEXT))
1714 if (!pull_utf8_talloc(mem_ctx,
1716 attr->values[0].string.text,
1720 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1728 * We have everything needed...
1739 ippDelete(response);
1746 cupsLangFree(language);
1756 /* this keeps fussy compilers happy */
1757 void print_cups_dummy(void);
1758 void print_cups_dummy(void) {}
1759 #endif /* HAVE_CUPS */