Fix bug #5080. Access to cups-printers via samba broken with cups 1.3.4, Unsupported...
[Samba.git] / source / printing / print_cups.c
blob0be65a58befc0a8544c0aeded960dce340a817c9
1 /*
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.
25 #include "includes.h"
26 #include "printing.h"
28 #ifdef HAVE_CUPS
29 #include <cups/cups.h>
30 #include <cups/language.h>
32 extern userdom_struct current_user_info;
35 * 'cups_passwd_cb()' - The CUPS password callback...
38 static const char * /* O - Password or NULL */
39 cups_passwd_cb(const char *prompt) /* I - Prompt */
42 * Always return NULL to indicate that no password is available...
45 return (NULL);
48 static http_t *cups_connect(TALLOC_CTX *frame)
50 http_t *http = NULL;
51 char *server = NULL, *p = NULL;
52 int port;
54 if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
55 if (push_utf8_talloc(frame, &server, lp_cups_server()) == (size_t)-1) {
56 return NULL;
58 } else {
59 server = talloc_strdup(frame,cupsServer());
61 if (!server) {
62 return NULL;
65 p = strchr(server, ':');
66 if (p) {
67 port = atoi(p+1);
68 *p = '\0';
69 } else {
70 port = ippPort();
73 DEBUG(10, ("connecting to cups server %s:%d\n",
74 server, port));
76 if ((http = httpConnect(server, port)) == NULL) {
77 DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n",
78 server, port, strerror(errno)));
79 return NULL;
82 return http;
85 bool cups_cache_reload(void)
87 TALLOC_CTX *frame = talloc_stackframe();
88 http_t *http = NULL; /* HTTP connection to server */
89 ipp_t *request = NULL, /* IPP Request */
90 *response = NULL; /* IPP Response */
91 ipp_attribute_t *attr; /* Current attribute */
92 cups_lang_t *language = NULL; /* Default language */
93 char *name, /* printer-name attribute */
94 *info; /* printer-info attribute */
95 static const char *requested[] =/* Requested attributes */
97 "printer-name",
98 "printer-info"
100 bool ret = False;
102 DEBUG(5, ("reloading cups printcap cache\n"));
105 * Make sure we don't ask for passwords...
108 cupsSetPasswordCB(cups_passwd_cb);
111 * Try to connect to the server...
114 if ((http = cups_connect(frame)) == NULL) {
115 goto out;
119 * Build a CUPS_GET_PRINTERS request, which requires the following
120 * attributes:
122 * attributes-charset
123 * attributes-natural-language
124 * requested-attributes
127 request = ippNew();
129 request->request.op.operation_id = CUPS_GET_PRINTERS;
130 request->request.op.request_id = 1;
132 language = cupsLangDefault();
134 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
135 "attributes-charset", NULL, "utf-8");
137 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
138 "attributes-natural-language", NULL, language->language);
140 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
141 "requested-attributes",
142 (sizeof(requested) / sizeof(requested[0])),
143 NULL, requested);
146 * Do the request and get back a response...
149 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
150 DEBUG(0,("Unable to get printer list - %s\n",
151 ippErrorString(cupsLastError())));
152 goto out;
155 for (attr = response->attrs; attr != NULL;) {
157 * Skip leading attributes until we hit a printer...
160 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
161 attr = attr->next;
163 if (attr == NULL)
164 break;
167 * Pull the needed attributes from this printer...
170 name = NULL;
171 info = NULL;
173 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
174 if (strcmp(attr->name, "printer-name") == 0 &&
175 attr->value_tag == IPP_TAG_NAME) {
176 pull_utf8_talloc(frame,
177 &name,
178 attr->values[0].string.text);
181 if (strcmp(attr->name, "printer-info") == 0 &&
182 attr->value_tag == IPP_TAG_TEXT) {
183 pull_utf8_talloc(frame,
184 &info,
185 attr->values[0].string.text);
188 attr = attr->next;
192 * See if we have everything needed...
195 if (name == NULL)
196 break;
198 if (!pcap_cache_add(name, info)) {
199 goto out;
203 ippDelete(response);
204 response = NULL;
207 * Build a CUPS_GET_CLASSES request, which requires the following
208 * attributes:
210 * attributes-charset
211 * attributes-natural-language
212 * requested-attributes
215 request = ippNew();
217 request->request.op.operation_id = CUPS_GET_CLASSES;
218 request->request.op.request_id = 1;
220 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
221 "attributes-charset", NULL, "utf-8");
223 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
224 "attributes-natural-language", NULL, language->language);
226 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
227 "requested-attributes",
228 (sizeof(requested) / sizeof(requested[0])),
229 NULL, requested);
232 * Do the request and get back a response...
235 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
236 DEBUG(0,("Unable to get printer list - %s\n",
237 ippErrorString(cupsLastError())));
238 goto out;
241 for (attr = response->attrs; attr != NULL;) {
243 * Skip leading attributes until we hit a printer...
246 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
247 attr = attr->next;
249 if (attr == NULL)
250 break;
253 * Pull the needed attributes from this printer...
256 name = NULL;
257 info = NULL;
259 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
260 if (strcmp(attr->name, "printer-name") == 0 &&
261 attr->value_tag == IPP_TAG_NAME) {
262 pull_utf8_talloc(frame,
263 &name,
264 attr->values[0].string.text);
267 if (strcmp(attr->name, "printer-info") == 0 &&
268 attr->value_tag == IPP_TAG_TEXT) {
269 pull_utf8_talloc(frame,
270 &info,
271 attr->values[0].string.text);
274 attr = attr->next;
278 * See if we have everything needed...
281 if (name == NULL)
282 break;
284 if (!pcap_cache_add(name, info)) {
285 goto out;
289 ret = True;
291 out:
292 if (response)
293 ippDelete(response);
295 if (language)
296 cupsLangFree(language);
298 if (http)
299 httpClose(http);
301 TALLOC_FREE(frame);
302 return ret;
307 * 'cups_job_delete()' - Delete a job.
310 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
312 TALLOC_CTX *frame = talloc_stackframe();
313 int ret = 1; /* Return value */
314 http_t *http = NULL; /* HTTP connection to server */
315 ipp_t *request = NULL, /* IPP Request */
316 *response = NULL; /* IPP Response */
317 cups_lang_t *language = NULL; /* Default language */
318 char *user = NULL;
319 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
322 DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
325 * Make sure we don't ask for passwords...
328 cupsSetPasswordCB(cups_passwd_cb);
331 * Try to connect to the server...
334 if ((http = cups_connect(frame)) == NULL) {
335 goto out;
339 * Build an IPP_CANCEL_JOB request, which requires the following
340 * attributes:
342 * attributes-charset
343 * attributes-natural-language
344 * job-uri
345 * requesting-user-name
348 request = ippNew();
350 request->request.op.operation_id = IPP_CANCEL_JOB;
351 request->request.op.request_id = 1;
353 language = cupsLangDefault();
355 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
356 "attributes-charset", NULL, "utf-8");
358 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
359 "attributes-natural-language", NULL, language->language);
361 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
363 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
365 if (push_utf8_talloc(frame, &user, pjob->user) == (size_t)-1) {
366 goto out;
369 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
370 NULL, user);
373 * Do the request and get back a response...
376 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
377 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
378 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
379 ippErrorString(cupsLastError())));
380 } else {
381 ret = 0;
383 } else {
384 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
385 ippErrorString(cupsLastError())));
388 out:
389 if (response)
390 ippDelete(response);
392 if (language)
393 cupsLangFree(language);
395 if (http)
396 httpClose(http);
398 TALLOC_FREE(frame);
399 return ret;
404 * 'cups_job_pause()' - Pause a job.
407 static int cups_job_pause(int snum, struct printjob *pjob)
409 TALLOC_CTX *frame = talloc_stackframe();
410 int ret = 1; /* Return value */
411 http_t *http = NULL; /* HTTP connection to server */
412 ipp_t *request = NULL, /* IPP Request */
413 *response = NULL; /* IPP Response */
414 cups_lang_t *language = NULL; /* Default language */
415 char *user = NULL;
416 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
419 DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
422 * Make sure we don't ask for passwords...
425 cupsSetPasswordCB(cups_passwd_cb);
428 * Try to connect to the server...
431 if ((http = cups_connect(frame)) == NULL) {
432 goto out;
436 * Build an IPP_HOLD_JOB request, which requires the following
437 * attributes:
439 * attributes-charset
440 * attributes-natural-language
441 * job-uri
442 * requesting-user-name
445 request = ippNew();
447 request->request.op.operation_id = IPP_HOLD_JOB;
448 request->request.op.request_id = 1;
450 language = cupsLangDefault();
452 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
453 "attributes-charset", NULL, "utf-8");
455 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
456 "attributes-natural-language", NULL, language->language);
458 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
460 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
462 if (push_utf8_talloc(frame, &user, pjob->user) == (size_t)-1) {
463 goto out;
465 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
466 NULL, user);
469 * Do the request and get back a response...
472 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
473 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
474 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
475 ippErrorString(cupsLastError())));
476 } else {
477 ret = 0;
479 } else {
480 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
481 ippErrorString(cupsLastError())));
484 out:
485 if (response)
486 ippDelete(response);
488 if (language)
489 cupsLangFree(language);
491 if (http)
492 httpClose(http);
494 TALLOC_FREE(frame);
495 return ret;
500 * 'cups_job_resume()' - Resume a paused job.
503 static int cups_job_resume(int snum, struct printjob *pjob)
505 TALLOC_CTX *frame = talloc_stackframe();
506 int ret = 1; /* Return value */
507 http_t *http = NULL; /* HTTP connection to server */
508 ipp_t *request = NULL, /* IPP Request */
509 *response = NULL; /* IPP Response */
510 cups_lang_t *language = NULL; /* Default language */
511 char *user = NULL;
512 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
515 DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
518 * Make sure we don't ask for passwords...
521 cupsSetPasswordCB(cups_passwd_cb);
524 * Try to connect to the server...
527 if ((http = cups_connect(frame)) == NULL) {
528 goto out;
532 * Build an IPP_RELEASE_JOB request, which requires the following
533 * attributes:
535 * attributes-charset
536 * attributes-natural-language
537 * job-uri
538 * requesting-user-name
541 request = ippNew();
543 request->request.op.operation_id = IPP_RELEASE_JOB;
544 request->request.op.request_id = 1;
546 language = cupsLangDefault();
548 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
549 "attributes-charset", NULL, "utf-8");
551 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
552 "attributes-natural-language", NULL, language->language);
554 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
556 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
558 if (push_utf8_talloc(frame, &user, pjob->user) == (size_t)-1) {
559 goto out;
561 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
562 NULL, user);
565 * Do the request and get back a response...
568 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
569 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
570 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
571 ippErrorString(cupsLastError())));
572 } else {
573 ret = 0;
575 } else {
576 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
577 ippErrorString(cupsLastError())));
580 out:
581 if (response)
582 ippDelete(response);
584 if (language)
585 cupsLangFree(language);
587 if (http)
588 httpClose(http);
590 TALLOC_FREE(frame);
591 return ret;
596 * 'cups_job_submit()' - Submit a job for printing.
599 static int cups_job_submit(int snum, struct printjob *pjob)
601 TALLOC_CTX *frame = talloc_stackframe();
602 int ret = 1; /* Return value */
603 http_t *http = NULL; /* HTTP connection to server */
604 ipp_t *request = NULL, /* IPP Request */
605 *response = NULL; /* IPP Response */
606 cups_lang_t *language = NULL; /* Default language */
607 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
608 const char *clientname = NULL; /* hostname of client for job-originating-host attribute */
609 char *new_jobname = NULL;
610 int num_options = 0;
611 cups_option_t *options = NULL;
612 char *printername = NULL;
613 char *user = NULL;
614 char *jobname = NULL;
615 char *cupsoptions = NULL;
616 char *filename = NULL;
617 char addr[INET6_ADDRSTRLEN];
619 DEBUG(5,("cups_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
622 * Make sure we don't ask for passwords...
625 cupsSetPasswordCB(cups_passwd_cb);
628 * Try to connect to the server...
631 if ((http = cups_connect(frame)) == NULL) {
632 goto out;
636 * Build an IPP_PRINT_JOB request, which requires the following
637 * attributes:
639 * attributes-charset
640 * attributes-natural-language
641 * printer-uri
642 * requesting-user-name
643 * [document-data]
646 request = ippNew();
648 request->request.op.operation_id = IPP_PRINT_JOB;
649 request->request.op.request_id = 1;
651 language = cupsLangDefault();
653 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
654 "attributes-charset", NULL, "utf-8");
656 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
657 "attributes-natural-language", NULL, language->language);
659 if (push_utf8_talloc(frame, &printername, PRINTERNAME(snum)) == (size_t)-1) {
660 goto out;
662 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
663 printername);
665 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
666 "printer-uri", NULL, uri);
668 if (push_utf8_talloc(frame, &user, pjob->user) == (size_t)-1) {
669 goto out;
671 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
672 NULL, user);
674 clientname = client_name(get_client_fd());
675 if (strcmp(clientname, "UNKNOWN") == 0) {
676 clientname = client_addr(get_client_fd(),addr,sizeof(addr));
679 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
680 "job-originating-host-name", NULL,
681 clientname);
683 if (push_utf8_talloc(frame, &jobname, pjob->jobname) == (size_t)-1) {
684 goto out;
686 new_jobname = talloc_asprintf(frame,
687 "%s%.8u %s", PRINT_SPOOL_PREFIX,
688 (unsigned int)pjob->smbjob,
689 jobname);
690 if (new_jobname == NULL) {
691 goto out;
694 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
695 new_jobname);
698 * add any options defined in smb.conf
701 if (push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum)) == (size_t)-1) {
702 goto out;
704 num_options = 0;
705 options = NULL;
706 num_options = cupsParseOptions(cupsoptions, num_options, &options);
708 if ( num_options )
709 cupsEncodeOptions(request, num_options, options);
712 * Do the request and get back a response...
715 slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
717 if (push_utf8_talloc(frame, &filename, pjob->filename) == (size_t)-1) {
718 goto out;
720 if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
721 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
722 DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum),
723 ippErrorString(cupsLastError())));
724 } else {
725 ret = 0;
727 } else {
728 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum),
729 ippErrorString(cupsLastError())));
732 if ( ret == 0 )
733 unlink(pjob->filename);
734 /* else print_job_end will do it for us */
736 out:
737 if (response)
738 ippDelete(response);
740 if (language)
741 cupsLangFree(language);
743 if (http)
744 httpClose(http);
746 TALLOC_FREE(frame);
748 return ret;
752 * 'cups_queue_get()' - Get all the jobs in the print queue.
755 static int cups_queue_get(const char *sharename,
756 enum printing_types printing_type,
757 char *lpq_command,
758 print_queue_struct **q,
759 print_status_struct *status)
761 TALLOC_CTX *frame = talloc_stackframe();
762 char *printername = NULL;
763 http_t *http = NULL; /* HTTP connection to server */
764 ipp_t *request = NULL, /* IPP Request */
765 *response = NULL; /* IPP Response */
766 ipp_attribute_t *attr = NULL; /* Current attribute */
767 cups_lang_t *language = NULL; /* Default language */
768 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
769 int qcount = 0, /* Number of active queue entries */
770 qalloc = 0; /* Number of queue entries allocated */
771 print_queue_struct *queue = NULL, /* Queue entries */
772 *temp; /* Temporary pointer for queue */
773 char *user_name = NULL, /* job-originating-user-name attribute */
774 *job_name = NULL; /* job-name attribute */
775 int job_id; /* job-id attribute */
776 int job_k_octets; /* job-k-octets attribute */
777 time_t job_time; /* time-at-creation attribute */
778 ipp_jstate_t job_status; /* job-status attribute */
779 int job_priority; /* job-priority attribute */
780 static const char *jattrs[] = /* Requested job attributes */
782 "job-id",
783 "job-k-octets",
784 "job-name",
785 "job-originating-user-name",
786 "job-priority",
787 "job-state",
788 "time-at-creation",
790 static const char *pattrs[] = /* Requested printer attributes */
792 "printer-state",
793 "printer-state-message"
796 *q = NULL;
798 /* HACK ALERT!!! The problem with support the 'printer name'
799 option is that we key the tdb off the sharename. So we will
800 overload the lpq_command string to pass in the printername
801 (which is basically what we do for non-cups printers ... using
802 the lpq_command to get the queue listing). */
804 if (push_utf8_talloc(frame, &printername, lpq_command) == (size_t)-1) {
805 goto out;
807 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
810 * Make sure we don't ask for passwords...
813 cupsSetPasswordCB(cups_passwd_cb);
816 * Try to connect to the server...
819 if ((http = cups_connect(frame)) == NULL) {
820 goto out;
824 * Generate the printer URI...
827 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
830 * Build an IPP_GET_JOBS request, which requires the following
831 * attributes:
833 * attributes-charset
834 * attributes-natural-language
835 * requested-attributes
836 * printer-uri
839 request = ippNew();
841 request->request.op.operation_id = IPP_GET_JOBS;
842 request->request.op.request_id = 1;
844 language = cupsLangDefault();
846 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
847 "attributes-charset", NULL, "utf-8");
849 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
850 "attributes-natural-language", NULL, language->language);
852 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
853 "requested-attributes",
854 (sizeof(jattrs) / sizeof(jattrs[0])),
855 NULL, jattrs);
857 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
858 "printer-uri", NULL, uri);
861 * Do the request and get back a response...
864 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
865 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
866 ippErrorString(cupsLastError())));
867 goto out;
870 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
871 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
872 ippErrorString(response->request.status.status_code)));
873 goto out;
877 * Process the jobs...
880 qcount = 0;
881 qalloc = 0;
882 queue = NULL;
884 for (attr = response->attrs; attr != NULL; attr = attr->next) {
886 * Skip leading attributes until we hit a job...
889 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
890 attr = attr->next;
892 if (attr == NULL)
893 break;
896 * Allocate memory as needed...
898 if (qcount >= qalloc) {
899 qalloc += 16;
901 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
903 if (queue == NULL) {
904 DEBUG(0,("cups_queue_get: Not enough memory!"));
905 qcount = 0;
906 goto out;
910 temp = queue + qcount;
911 memset(temp, 0, sizeof(print_queue_struct));
914 * Pull the needed attributes from this job...
917 job_id = 0;
918 job_priority = 50;
919 job_status = IPP_JOB_PENDING;
920 job_time = 0;
921 job_k_octets = 0;
922 user_name = NULL;
923 job_name = NULL;
925 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
926 if (attr->name == NULL) {
927 attr = attr->next;
928 break;
931 if (strcmp(attr->name, "job-id") == 0 &&
932 attr->value_tag == IPP_TAG_INTEGER)
933 job_id = attr->values[0].integer;
935 if (strcmp(attr->name, "job-k-octets") == 0 &&
936 attr->value_tag == IPP_TAG_INTEGER)
937 job_k_octets = attr->values[0].integer;
939 if (strcmp(attr->name, "job-priority") == 0 &&
940 attr->value_tag == IPP_TAG_INTEGER)
941 job_priority = attr->values[0].integer;
943 if (strcmp(attr->name, "job-state") == 0 &&
944 attr->value_tag == IPP_TAG_ENUM)
945 job_status = (ipp_jstate_t)(attr->values[0].integer);
947 if (strcmp(attr->name, "time-at-creation") == 0 &&
948 attr->value_tag == IPP_TAG_INTEGER)
949 job_time = attr->values[0].integer;
951 if (strcmp(attr->name, "job-name") == 0 &&
952 attr->value_tag == IPP_TAG_NAME) {
953 pull_utf8_talloc(frame,
954 &job_name,
955 attr->values[0].string.text);
958 if (strcmp(attr->name, "job-originating-user-name") == 0 &&
959 attr->value_tag == IPP_TAG_NAME) {
960 pull_utf8_talloc(frame,
961 &user_name,
962 attr->values[0].string.text);
965 attr = attr->next;
969 * See if we have everything needed...
972 if (user_name == NULL || job_name == NULL || job_id == 0) {
973 if (attr == NULL)
974 break;
975 else
976 continue;
979 temp->job = job_id;
980 temp->size = job_k_octets * 1024;
981 temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
982 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
983 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
984 LPQ_PRINTING;
985 temp->priority = job_priority;
986 temp->time = job_time;
987 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
988 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
990 qcount ++;
992 if (attr == NULL)
993 break;
996 ippDelete(response);
997 response = NULL;
1000 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1001 * following attributes:
1003 * attributes-charset
1004 * attributes-natural-language
1005 * requested-attributes
1006 * printer-uri
1009 request = ippNew();
1011 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1012 request->request.op.request_id = 1;
1014 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1015 "attributes-charset", NULL, "utf-8");
1017 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1018 "attributes-natural-language", NULL, language->language);
1020 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1021 "requested-attributes",
1022 (sizeof(pattrs) / sizeof(pattrs[0])),
1023 NULL, pattrs);
1025 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1026 "printer-uri", NULL, uri);
1029 * Do the request and get back a response...
1032 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1033 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1034 ippErrorString(cupsLastError())));
1035 *q = queue;
1036 goto out;
1039 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1040 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1041 ippErrorString(response->request.status.status_code)));
1042 *q = queue;
1043 goto out;
1047 * Get the current printer status and convert it to the SAMBA values.
1050 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1051 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1052 status->status = LPSTAT_STOPPED;
1053 else
1054 status->status = LPSTAT_OK;
1057 if ((attr = ippFindAttribute(response, "printer-state-message",
1058 IPP_TAG_TEXT)) != NULL) {
1059 char *msg = NULL;
1060 pull_utf8_talloc(frame, &msg, attr->values[0].string.text);
1061 fstrcpy(status->message, msg);
1065 * Return the job queue...
1068 *q = queue;
1070 out:
1071 if (response)
1072 ippDelete(response);
1074 if (language)
1075 cupsLangFree(language);
1077 if (http)
1078 httpClose(http);
1080 TALLOC_FREE(frame);
1081 return qcount;
1086 * 'cups_queue_pause()' - Pause a print queue.
1089 static int cups_queue_pause(int snum)
1091 TALLOC_CTX *frame = talloc_stackframe();
1092 int ret = 1; /* Return value */
1093 http_t *http = NULL; /* HTTP connection to server */
1094 ipp_t *request = NULL, /* IPP Request */
1095 *response = NULL; /* IPP Response */
1096 cups_lang_t *language = NULL; /* Default language */
1097 char *printername = NULL;
1098 char *username = NULL;
1099 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1102 DEBUG(5,("cups_queue_pause(%d)\n", snum));
1105 * Make sure we don't ask for passwords...
1108 cupsSetPasswordCB(cups_passwd_cb);
1111 * Try to connect to the server...
1114 if ((http = cups_connect(frame)) == NULL) {
1115 goto out;
1119 * Build an IPP_PAUSE_PRINTER request, which requires the following
1120 * attributes:
1122 * attributes-charset
1123 * attributes-natural-language
1124 * printer-uri
1125 * requesting-user-name
1128 request = ippNew();
1130 request->request.op.operation_id = IPP_PAUSE_PRINTER;
1131 request->request.op.request_id = 1;
1133 language = cupsLangDefault();
1135 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1136 "attributes-charset", NULL, "utf-8");
1138 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1139 "attributes-natural-language", NULL, language->language);
1141 if (push_utf8_talloc(frame, &printername, PRINTERNAME(snum)) == (size_t)-1) {
1142 goto out;
1144 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1145 printername);
1147 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1149 if (push_utf8_talloc(frame, &username, current_user_info.unix_name) == (size_t)-1) {
1150 goto out;
1152 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1153 NULL, username);
1156 * Do the request and get back a response...
1159 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1160 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1161 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1162 ippErrorString(cupsLastError())));
1163 } else {
1164 ret = 0;
1166 } else {
1167 DEBUG(0,("Unable to pause printer %s - %s\n", PRINTERNAME(snum),
1168 ippErrorString(cupsLastError())));
1171 out:
1172 if (response)
1173 ippDelete(response);
1175 if (language)
1176 cupsLangFree(language);
1178 if (http)
1179 httpClose(http);
1181 TALLOC_FREE(frame);
1182 return ret;
1187 * 'cups_queue_resume()' - Restart a print queue.
1190 static int cups_queue_resume(int snum)
1192 TALLOC_CTX *frame = talloc_stackframe();
1193 int ret = 1; /* Return value */
1194 http_t *http = NULL; /* HTTP connection to server */
1195 ipp_t *request = NULL, /* IPP Request */
1196 *response = NULL; /* IPP Response */
1197 cups_lang_t *language = NULL; /* Default language */
1198 char *printername = NULL;
1199 char *username = NULL;
1200 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1203 DEBUG(5,("cups_queue_resume(%d)\n", snum));
1206 * Make sure we don't ask for passwords...
1209 cupsSetPasswordCB(cups_passwd_cb);
1212 * Try to connect to the server...
1215 if ((http = cups_connect(frame)) == NULL) {
1216 goto out;
1220 * Build an IPP_RESUME_PRINTER request, which requires the following
1221 * attributes:
1223 * attributes-charset
1224 * attributes-natural-language
1225 * printer-uri
1226 * requesting-user-name
1229 request = ippNew();
1231 request->request.op.operation_id = IPP_RESUME_PRINTER;
1232 request->request.op.request_id = 1;
1234 language = cupsLangDefault();
1236 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1237 "attributes-charset", NULL, "utf-8");
1239 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1240 "attributes-natural-language", NULL, language->language);
1242 if (push_utf8_talloc(frame, &printername, PRINTERNAME(snum)) == (size_t)-1) {
1243 goto out;
1245 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1246 printername);
1248 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1250 if (push_utf8_talloc(frame, &username, current_user_info.unix_name) == (size_t)-1) {
1251 goto out;
1253 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1254 NULL, username);
1257 * Do the request and get back a response...
1260 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1261 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1262 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1263 ippErrorString(cupsLastError())));
1264 } else {
1265 ret = 0;
1267 } else {
1268 DEBUG(0,("Unable to resume printer %s - %s\n", PRINTERNAME(snum),
1269 ippErrorString(cupsLastError())));
1272 out:
1273 if (response)
1274 ippDelete(response);
1276 if (language)
1277 cupsLangFree(language);
1279 if (http)
1280 httpClose(http);
1282 TALLOC_FREE(frame);
1283 return ret;
1286 /*******************************************************************
1287 * CUPS printing interface definitions...
1288 ******************************************************************/
1290 struct printif cups_printif =
1292 PRINT_CUPS,
1293 cups_queue_get,
1294 cups_queue_pause,
1295 cups_queue_resume,
1296 cups_job_delete,
1297 cups_job_pause,
1298 cups_job_resume,
1299 cups_job_submit,
1302 bool cups_pull_comment_location(NT_PRINTER_INFO_LEVEL_2 *printer)
1304 TALLOC_CTX *frame = talloc_stackframe();
1305 http_t *http = NULL; /* HTTP connection to server */
1306 ipp_t *request = NULL, /* IPP Request */
1307 *response = NULL; /* IPP Response */
1308 ipp_attribute_t *attr; /* Current attribute */
1309 cups_lang_t *language = NULL; /* Default language */
1310 char uri[HTTP_MAX_URI];
1311 char *server = NULL;
1312 char *sharename = NULL;
1313 char *name = NULL;
1314 static const char *requested[] =/* Requested attributes */
1316 "printer-name",
1317 "printer-info",
1318 "printer-location"
1320 bool ret = False;
1322 DEBUG(5, ("pulling %s location\n", printer->sharename));
1325 * Make sure we don't ask for passwords...
1328 cupsSetPasswordCB(cups_passwd_cb);
1331 * Try to connect to the server...
1334 if ((http = cups_connect(frame)) == NULL) {
1335 goto out;
1338 request = ippNew();
1340 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1341 request->request.op.request_id = 1;
1343 language = cupsLangDefault();
1345 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1346 "attributes-charset", NULL, "utf-8");
1348 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1349 "attributes-natural-language", NULL, language->language);
1351 if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1352 if (push_utf8_talloc(frame, &server, lp_cups_server()) == (size_t)-1) {
1353 goto out;
1355 } else {
1356 server = talloc_strdup(frame,cupsServer());
1358 if (server) {
1359 goto out;
1361 if (push_utf8_talloc(frame, &sharename, printer->sharename) == (size_t)-1) {
1362 goto out;
1364 slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1365 server, sharename);
1367 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1368 "printer-uri", NULL, uri);
1370 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1371 "requested-attributes",
1372 (sizeof(requested) / sizeof(requested[0])),
1373 NULL, requested);
1376 * Do the request and get back a response...
1379 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1380 DEBUG(0,("Unable to get printer attributes - %s\n",
1381 ippErrorString(cupsLastError())));
1382 goto out;
1385 for (attr = response->attrs; attr != NULL;) {
1387 * Skip leading attributes until we hit a printer...
1390 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1391 attr = attr->next;
1393 if (attr == NULL)
1394 break;
1397 * Pull the needed attributes from this printer...
1400 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1401 if (strcmp(attr->name, "printer-name") == 0 &&
1402 attr->value_tag == IPP_TAG_NAME) {
1403 pull_utf8_talloc(frame,
1404 &name,
1405 attr->values[0].string.text);
1408 /* Grab the comment if we don't have one */
1409 if ( (strcmp(attr->name, "printer-info") == 0)
1410 && (attr->value_tag == IPP_TAG_TEXT)
1411 && !strlen(printer->comment) )
1413 char *comment = NULL;
1414 pull_utf8_talloc(frame,
1415 &comment,
1416 attr->values[0].string.text);
1417 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1418 comment));
1419 strlcpy(printer->comment,
1420 comment,
1421 sizeof(printer->comment));
1424 /* Grab the location if we don't have one */
1425 if ( (strcmp(attr->name, "printer-location") == 0)
1426 && (attr->value_tag == IPP_TAG_TEXT)
1427 && !strlen(printer->location) )
1429 char *location = NULL;
1430 pull_utf8_talloc(frame,
1431 &location,
1432 attr->values[0].string.text);
1433 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1434 location));
1435 strlcpy(printer->location,
1436 location,
1437 sizeof(printer->location));
1440 attr = attr->next;
1444 * We have everything needed...
1447 if (name != NULL)
1448 break;
1451 ret = True;
1453 out:
1454 if (response)
1455 ippDelete(response);
1457 if (language)
1458 cupsLangFree(language);
1460 if (http)
1461 httpClose(http);
1463 TALLOC_FREE(frame);
1464 return ret;
1467 #else
1468 /* this keeps fussy compilers happy */
1469 void print_cups_dummy(void);
1470 void print_cups_dummy(void) {}
1471 #endif /* HAVE_CUPS */