nsswitch: fix a segfault in the krb5 locator plugin
[Samba/wip.git] / source3 / printing / print_cups.c
blob0e5dac53746a9d32ee51b17eb51d3caf05cf39cb
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"
27 #include "printing/pcap.h"
29 #ifdef HAVE_CUPS
30 #include <cups/cups.h>
31 #include <cups/language.h>
33 static SIG_ATOMIC_T gotalarm;
35 /***************************************************************
36 Signal function to tell us we timed out.
37 ****************************************************************/
39 static void gotalarm_sig(int signum)
41 gotalarm = 1;
44 extern userdom_struct current_user_info;
47 * 'cups_passwd_cb()' - The CUPS password callback...
50 static const char * /* O - Password or NULL */
51 cups_passwd_cb(const char *prompt) /* I - Prompt */
54 * Always return NULL to indicate that no password is available...
57 return (NULL);
60 static http_t *cups_connect(TALLOC_CTX *frame)
62 http_t *http = NULL;
63 char *server = NULL, *p = NULL;
64 int port;
65 int timeout = lp_cups_connection_timeout();
66 size_t size;
68 if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
69 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
70 return NULL;
72 } else {
73 server = talloc_strdup(frame,cupsServer());
75 if (!server) {
76 return NULL;
79 p = strchr(server, ':');
80 if (p) {
81 port = atoi(p+1);
82 *p = '\0';
83 } else {
84 port = ippPort();
87 DEBUG(10, ("connecting to cups server %s:%d\n",
88 server, port));
90 gotalarm = 0;
92 if (timeout) {
93 CatchSignal(SIGALRM, gotalarm_sig);
94 alarm(timeout);
97 #ifdef HAVE_HTTPCONNECTENCRYPT
98 http = httpConnectEncrypt(server, port, lp_cups_encrypt());
99 #else
100 http = httpConnect(server, port);
101 #endif
104 CatchSignal(SIGALRM, SIG_IGN);
105 alarm(0);
107 if (http == NULL) {
108 DEBUG(0,("Unable to connect to CUPS server %s:%d - %s\n",
109 server, port, strerror(errno)));
112 return http;
115 static void send_pcap_info(const char *name, const char *info, void *pd)
117 int fd = *(int *)pd;
118 size_t namelen = name ? strlen(name)+1 : 0;
119 size_t infolen = info ? strlen(info)+1 : 0;
121 DEBUG(11,("send_pcap_info: writing namelen %u\n", (unsigned int)namelen));
122 if (sys_write(fd, &namelen, sizeof(namelen)) != sizeof(namelen)) {
123 DEBUG(10,("send_pcap_info: namelen write failed %s\n",
124 strerror(errno)));
125 return;
127 DEBUG(11,("send_pcap_info: writing infolen %u\n", (unsigned int)infolen));
128 if (sys_write(fd, &infolen, sizeof(infolen)) != sizeof(infolen)) {
129 DEBUG(10,("send_pcap_info: infolen write failed %s\n",
130 strerror(errno)));
131 return;
133 if (namelen) {
134 DEBUG(11,("send_pcap_info: writing name %s\n", name));
135 if (sys_write(fd, name, namelen) != namelen) {
136 DEBUG(10,("send_pcap_info: name write failed %s\n",
137 strerror(errno)));
138 return;
141 if (infolen) {
142 DEBUG(11,("send_pcap_info: writing info %s\n", info));
143 if (sys_write(fd, info, infolen) != infolen) {
144 DEBUG(10,("send_pcap_info: info write failed %s\n",
145 strerror(errno)));
146 return;
151 static bool cups_cache_reload_async(int fd)
153 TALLOC_CTX *frame = talloc_stackframe();
154 struct pcap_cache *tmp_pcap_cache = NULL;
155 http_t *http = NULL; /* HTTP connection to server */
156 ipp_t *request = NULL, /* IPP Request */
157 *response = NULL; /* IPP Response */
158 ipp_attribute_t *attr; /* Current attribute */
159 cups_lang_t *language = NULL; /* Default language */
160 char *name, /* printer-name attribute */
161 *info; /* printer-info attribute */
162 static const char *requested[] =/* Requested attributes */
164 "printer-name",
165 "printer-info"
167 bool ret = False;
168 size_t size;
170 DEBUG(5, ("reloading cups printcap cache\n"));
173 * Make sure we don't ask for passwords...
176 cupsSetPasswordCB(cups_passwd_cb);
179 * Try to connect to the server...
182 if ((http = cups_connect(frame)) == NULL) {
183 goto out;
187 * Build a CUPS_GET_PRINTERS request, which requires the following
188 * attributes:
190 * attributes-charset
191 * attributes-natural-language
192 * requested-attributes
195 request = ippNew();
197 request->request.op.operation_id = CUPS_GET_PRINTERS;
198 request->request.op.request_id = 1;
200 language = cupsLangDefault();
202 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
203 "attributes-charset", NULL, "utf-8");
205 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
206 "attributes-natural-language", NULL, language->language);
208 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
209 "requested-attributes",
210 (sizeof(requested) / sizeof(requested[0])),
211 NULL, requested);
214 * Do the request and get back a response...
217 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
218 DEBUG(0,("Unable to get printer list - %s\n",
219 ippErrorString(cupsLastError())));
220 goto out;
223 for (attr = response->attrs; attr != NULL;) {
225 * Skip leading attributes until we hit a printer...
228 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
229 attr = attr->next;
231 if (attr == NULL)
232 break;
235 * Pull the needed attributes from this printer...
238 name = NULL;
239 info = NULL;
241 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
242 if (strcmp(attr->name, "printer-name") == 0 &&
243 attr->value_tag == IPP_TAG_NAME) {
244 if (!pull_utf8_talloc(frame,
245 &name,
246 attr->values[0].string.text,
247 &size)) {
248 goto out;
252 if (strcmp(attr->name, "printer-info") == 0 &&
253 attr->value_tag == IPP_TAG_TEXT) {
254 if (!pull_utf8_talloc(frame,
255 &info,
256 attr->values[0].string.text,
257 &size)) {
258 goto out;
262 attr = attr->next;
266 * See if we have everything needed...
269 if (name == NULL)
270 break;
272 if (!pcap_cache_add_specific(&tmp_pcap_cache, name, info)) {
273 goto out;
277 ippDelete(response);
278 response = NULL;
281 * Build a CUPS_GET_CLASSES request, which requires the following
282 * attributes:
284 * attributes-charset
285 * attributes-natural-language
286 * requested-attributes
289 request = ippNew();
291 request->request.op.operation_id = CUPS_GET_CLASSES;
292 request->request.op.request_id = 1;
294 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
295 "attributes-charset", NULL, "utf-8");
297 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
298 "attributes-natural-language", NULL, language->language);
300 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
301 "requested-attributes",
302 (sizeof(requested) / sizeof(requested[0])),
303 NULL, requested);
306 * Do the request and get back a response...
309 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
310 DEBUG(0,("Unable to get printer list - %s\n",
311 ippErrorString(cupsLastError())));
312 goto out;
315 for (attr = response->attrs; attr != NULL;) {
317 * Skip leading attributes until we hit a printer...
320 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
321 attr = attr->next;
323 if (attr == NULL)
324 break;
327 * Pull the needed attributes from this printer...
330 name = NULL;
331 info = NULL;
333 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) {
334 if (strcmp(attr->name, "printer-name") == 0 &&
335 attr->value_tag == IPP_TAG_NAME) {
336 if (!pull_utf8_talloc(frame,
337 &name,
338 attr->values[0].string.text,
339 &size)) {
340 goto out;
344 if (strcmp(attr->name, "printer-info") == 0 &&
345 attr->value_tag == IPP_TAG_TEXT) {
346 if (!pull_utf8_talloc(frame,
347 &info,
348 attr->values[0].string.text,
349 &size)) {
350 goto out;
354 attr = attr->next;
358 * See if we have everything needed...
361 if (name == NULL)
362 break;
364 if (!pcap_cache_add_specific(&tmp_pcap_cache, name, info)) {
365 goto out;
369 ret = True;
371 out:
372 if (response)
373 ippDelete(response);
375 if (language)
376 cupsLangFree(language);
378 if (http)
379 httpClose(http);
381 /* Send all the entries up the pipe. */
382 if (tmp_pcap_cache) {
383 pcap_printer_fn_specific(tmp_pcap_cache,
384 send_pcap_info,
385 (void *)&fd);
387 pcap_cache_destroy_specific(&tmp_pcap_cache);
389 TALLOC_FREE(frame);
390 return ret;
393 static struct pcap_cache *local_pcap_copy;
394 struct fd_event *cache_fd_event;
396 static bool cups_pcap_load_async(struct tevent_context *ev,
397 struct messaging_context *msg_ctx,
398 int *pfd)
400 int fds[2];
401 pid_t pid;
402 NTSTATUS status;
404 *pfd = -1;
406 if (cache_fd_event) {
407 DEBUG(3,("cups_pcap_load_async: already waiting for "
408 "a refresh event\n" ));
409 return false;
412 DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n"));
414 if (pipe(fds) == -1) {
415 return false;
418 pid = sys_fork();
419 if (pid == (pid_t)-1) {
420 DEBUG(10,("cups_pcap_load_async: fork failed %s\n",
421 strerror(errno) ));
422 close(fds[0]);
423 close(fds[1]);
424 return false;
427 if (pid) {
428 DEBUG(10,("cups_pcap_load_async: child pid = %u\n",
429 (unsigned int)pid ));
430 /* Parent. */
431 close(fds[1]);
432 *pfd = fds[0];
433 return true;
436 /* Child. */
438 close_all_print_db();
440 status = reinit_after_fork(msg_ctx, ev, procid_self(), true);
441 if (!NT_STATUS_IS_OK(status)) {
442 DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
443 smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
446 close(fds[0]);
447 cups_cache_reload_async(fds[1]);
448 close(fds[1]);
449 _exit(0);
452 struct cups_async_cb_args {
453 int pipe_fd;
454 struct event_context *event_ctx;
455 struct messaging_context *msg_ctx;
456 void (*post_cache_fill_fn)(struct event_context *,
457 struct messaging_context *);
460 static void cups_async_callback(struct event_context *event_ctx,
461 struct fd_event *event,
462 uint16 flags,
463 void *p)
465 TALLOC_CTX *frame = talloc_stackframe();
466 struct cups_async_cb_args *cb_args = (struct cups_async_cb_args *)p;
467 int fd = cb_args->pipe_fd;
468 struct pcap_cache *tmp_pcap_cache = NULL;
470 DEBUG(5,("cups_async_callback: callback received for printer data. "
471 "fd = %d\n", fd));
473 while (1) {
474 char *name = NULL, *info = NULL;
475 size_t namelen = 0, infolen = 0;
476 ssize_t ret = -1;
478 ret = sys_read(fd, &namelen, sizeof(namelen));
479 if (ret == 0) {
480 /* EOF */
481 break;
483 if (ret != sizeof(namelen)) {
484 DEBUG(10,("cups_async_callback: namelen read failed %d %s\n",
485 errno, strerror(errno)));
486 break;
489 DEBUG(11,("cups_async_callback: read namelen %u\n",
490 (unsigned int)namelen));
492 ret = sys_read(fd, &infolen, sizeof(infolen));
493 if (ret == 0) {
494 /* EOF */
495 break;
497 if (ret != sizeof(infolen)) {
498 DEBUG(10,("cups_async_callback: infolen read failed %s\n",
499 strerror(errno)));
500 break;
503 DEBUG(11,("cups_async_callback: read infolen %u\n",
504 (unsigned int)infolen));
506 if (namelen) {
507 name = TALLOC_ARRAY(frame, char, namelen);
508 if (!name) {
509 break;
511 ret = sys_read(fd, name, namelen);
512 if (ret == 0) {
513 /* EOF */
514 break;
516 if (ret != namelen) {
517 DEBUG(10,("cups_async_callback: name read failed %s\n",
518 strerror(errno)));
519 break;
521 DEBUG(11,("cups_async_callback: read name %s\n",
522 name));
523 } else {
524 name = NULL;
526 if (infolen) {
527 info = TALLOC_ARRAY(frame, char, infolen);
528 if (!info) {
529 break;
531 ret = sys_read(fd, info, infolen);
532 if (ret == 0) {
533 /* EOF */
534 break;
536 if (ret != infolen) {
537 DEBUG(10,("cups_async_callback: info read failed %s\n",
538 strerror(errno)));
539 break;
541 DEBUG(11,("cups_async_callback: read info %s\n",
542 info));
543 } else {
544 info = NULL;
547 /* Add to our local pcap cache. */
548 pcap_cache_add_specific(&tmp_pcap_cache, name, info);
549 TALLOC_FREE(name);
550 TALLOC_FREE(info);
553 TALLOC_FREE(frame);
554 if (tmp_pcap_cache) {
555 bool ret;
556 /* We got a namelist, replace our local cache. */
557 pcap_cache_destroy_specific(&local_pcap_copy);
558 local_pcap_copy = tmp_pcap_cache;
560 /* And the systemwide pcap cache. */
561 ret = pcap_cache_replace(local_pcap_copy);
562 if (!ret)
563 DEBUG(0, ("failed to replace pcap cache\n"));
565 /* Caller may have requested post cache fill callback */
566 if (ret && cb_args->post_cache_fill_fn != NULL) {
567 cb_args->post_cache_fill_fn(cb_args->event_ctx,
568 cb_args->msg_ctx);
570 } else {
571 DEBUG(2,("cups_async_callback: failed to read a new "
572 "printer list\n"));
574 close(fd);
575 TALLOC_FREE(cb_args);
576 TALLOC_FREE(cache_fd_event);
579 bool cups_cache_reload(struct tevent_context *ev,
580 struct messaging_context *msg_ctx,
581 void (*post_cache_fill_fn)(struct tevent_context *,
582 struct messaging_context *))
584 struct cups_async_cb_args *cb_args;
585 int *p_pipe_fd;
587 cb_args = TALLOC_P(NULL, struct cups_async_cb_args);
588 if (cb_args == NULL) {
589 return false;
592 cb_args->post_cache_fill_fn = post_cache_fill_fn;
593 cb_args->event_ctx = ev;
594 cb_args->msg_ctx = msg_ctx;
595 p_pipe_fd = &cb_args->pipe_fd;
596 *p_pipe_fd = -1;
598 /* Set up an async refresh. */
599 if (!cups_pcap_load_async(ev, msg_ctx, p_pipe_fd)) {
600 talloc_free(cb_args);
601 return false;
603 if (!local_pcap_copy) {
604 /* We have no local cache, wait directly for
605 * async refresh to complete.
607 DEBUG(10,("cups_cache_reload: sync read on fd %d\n",
608 *p_pipe_fd ));
610 cups_async_callback(ev, NULL,
611 EVENT_FD_READ,
612 (void *)cb_args);
613 if (!local_pcap_copy) {
614 return false;
616 } else {
617 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
618 *p_pipe_fd ));
620 /* Trigger an event when the pipe can be read. */
621 cache_fd_event = event_add_fd(ev,
622 NULL, *p_pipe_fd,
623 EVENT_FD_READ,
624 cups_async_callback,
625 (void *)cb_args);
626 if (!cache_fd_event) {
627 close(*p_pipe_fd);
628 TALLOC_FREE(cb_args);
629 return false;
632 return true;
636 * 'cups_job_delete()' - Delete a job.
639 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
641 TALLOC_CTX *frame = talloc_stackframe();
642 int ret = 1; /* Return value */
643 http_t *http = NULL; /* HTTP connection to server */
644 ipp_t *request = NULL, /* IPP Request */
645 *response = NULL; /* IPP Response */
646 cups_lang_t *language = NULL; /* Default language */
647 char *user = NULL;
648 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
649 size_t size;
651 DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
654 * Make sure we don't ask for passwords...
657 cupsSetPasswordCB(cups_passwd_cb);
660 * Try to connect to the server...
663 if ((http = cups_connect(frame)) == NULL) {
664 goto out;
668 * Build an IPP_CANCEL_JOB request, which requires the following
669 * attributes:
671 * attributes-charset
672 * attributes-natural-language
673 * job-uri
674 * requesting-user-name
677 request = ippNew();
679 request->request.op.operation_id = IPP_CANCEL_JOB;
680 request->request.op.request_id = 1;
682 language = cupsLangDefault();
684 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
685 "attributes-charset", NULL, "utf-8");
687 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
688 "attributes-natural-language", NULL, language->language);
690 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
692 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
694 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
695 goto out;
698 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
699 NULL, user);
702 * Do the request and get back a response...
705 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
706 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
707 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
708 ippErrorString(cupsLastError())));
709 } else {
710 ret = 0;
712 } else {
713 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
714 ippErrorString(cupsLastError())));
717 out:
718 if (response)
719 ippDelete(response);
721 if (language)
722 cupsLangFree(language);
724 if (http)
725 httpClose(http);
727 TALLOC_FREE(frame);
728 return ret;
733 * 'cups_job_pause()' - Pause a job.
736 static int cups_job_pause(int snum, struct printjob *pjob)
738 TALLOC_CTX *frame = talloc_stackframe();
739 int ret = 1; /* Return value */
740 http_t *http = NULL; /* HTTP connection to server */
741 ipp_t *request = NULL, /* IPP Request */
742 *response = NULL; /* IPP Response */
743 cups_lang_t *language = NULL; /* Default language */
744 char *user = NULL;
745 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
746 size_t size;
748 DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
751 * Make sure we don't ask for passwords...
754 cupsSetPasswordCB(cups_passwd_cb);
757 * Try to connect to the server...
760 if ((http = cups_connect(frame)) == NULL) {
761 goto out;
765 * Build an IPP_HOLD_JOB request, which requires the following
766 * attributes:
768 * attributes-charset
769 * attributes-natural-language
770 * job-uri
771 * requesting-user-name
774 request = ippNew();
776 request->request.op.operation_id = IPP_HOLD_JOB;
777 request->request.op.request_id = 1;
779 language = cupsLangDefault();
781 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
782 "attributes-charset", NULL, "utf-8");
784 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
785 "attributes-natural-language", NULL, language->language);
787 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
789 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
791 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
792 goto out;
794 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
795 NULL, user);
798 * Do the request and get back a response...
801 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
802 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
803 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
804 ippErrorString(cupsLastError())));
805 } else {
806 ret = 0;
808 } else {
809 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
810 ippErrorString(cupsLastError())));
813 out:
814 if (response)
815 ippDelete(response);
817 if (language)
818 cupsLangFree(language);
820 if (http)
821 httpClose(http);
823 TALLOC_FREE(frame);
824 return ret;
829 * 'cups_job_resume()' - Resume a paused job.
832 static int cups_job_resume(int snum, struct printjob *pjob)
834 TALLOC_CTX *frame = talloc_stackframe();
835 int ret = 1; /* Return value */
836 http_t *http = NULL; /* HTTP connection to server */
837 ipp_t *request = NULL, /* IPP Request */
838 *response = NULL; /* IPP Response */
839 cups_lang_t *language = NULL; /* Default language */
840 char *user = NULL;
841 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
842 size_t size;
844 DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
847 * Make sure we don't ask for passwords...
850 cupsSetPasswordCB(cups_passwd_cb);
853 * Try to connect to the server...
856 if ((http = cups_connect(frame)) == NULL) {
857 goto out;
861 * Build an IPP_RELEASE_JOB request, which requires the following
862 * attributes:
864 * attributes-charset
865 * attributes-natural-language
866 * job-uri
867 * requesting-user-name
870 request = ippNew();
872 request->request.op.operation_id = IPP_RELEASE_JOB;
873 request->request.op.request_id = 1;
875 language = cupsLangDefault();
877 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
878 "attributes-charset", NULL, "utf-8");
880 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
881 "attributes-natural-language", NULL, language->language);
883 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/jobs/%d", pjob->sysjob);
885 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
887 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
888 goto out;
890 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
891 NULL, user);
894 * Do the request and get back a response...
897 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
898 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
899 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
900 ippErrorString(cupsLastError())));
901 } else {
902 ret = 0;
904 } else {
905 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
906 ippErrorString(cupsLastError())));
909 out:
910 if (response)
911 ippDelete(response);
913 if (language)
914 cupsLangFree(language);
916 if (http)
917 httpClose(http);
919 TALLOC_FREE(frame);
920 return ret;
925 * 'cups_job_submit()' - Submit a job for printing.
928 static int cups_job_submit(int snum, struct printjob *pjob)
930 TALLOC_CTX *frame = talloc_stackframe();
931 int ret = 1; /* Return value */
932 http_t *http = NULL; /* HTTP connection to server */
933 ipp_t *request = NULL, /* IPP Request */
934 *response = NULL; /* IPP Response */
935 ipp_attribute_t *attr_job_id = NULL; /* IPP Attribute "job-id" */
936 cups_lang_t *language = NULL; /* Default language */
937 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
938 char *new_jobname = NULL;
939 int num_options = 0;
940 cups_option_t *options = NULL;
941 char *printername = NULL;
942 char *user = NULL;
943 char *jobname = NULL;
944 char *cupsoptions = NULL;
945 char *filename = NULL;
946 size_t size;
947 uint32_t jobid = (uint32_t)-1;
949 DEBUG(5,("cups_job_submit(%d, %p)\n", snum, pjob));
952 * Make sure we don't ask for passwords...
955 cupsSetPasswordCB(cups_passwd_cb);
958 * Try to connect to the server...
961 if ((http = cups_connect(frame)) == NULL) {
962 goto out;
966 * Build an IPP_PRINT_JOB request, which requires the following
967 * attributes:
969 * attributes-charset
970 * attributes-natural-language
971 * printer-uri
972 * requesting-user-name
973 * [document-data]
976 request = ippNew();
978 request->request.op.operation_id = IPP_PRINT_JOB;
979 request->request.op.request_id = 1;
981 language = cupsLangDefault();
983 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
984 "attributes-charset", NULL, "utf-8");
986 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
987 "attributes-natural-language", NULL, language->language);
989 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
990 &size)) {
991 goto out;
993 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
994 printername);
996 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
997 "printer-uri", NULL, uri);
999 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
1000 goto out;
1002 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1003 NULL, user);
1005 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1006 "job-originating-host-name", NULL,
1007 pjob->clientmachine);
1009 /* Get the jobid from the filename. */
1010 jobid = print_parse_jobid(pjob->filename);
1011 if (jobid == (uint32_t)-1) {
1012 DEBUG(0,("cups_job_submit: failed to parse jobid from name %s\n",
1013 pjob->filename ));
1014 jobid = 0;
1017 if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
1018 goto out;
1020 new_jobname = talloc_asprintf(frame,
1021 "%s%.8u %s", PRINT_SPOOL_PREFIX,
1022 (unsigned int)jobid,
1023 jobname);
1024 if (new_jobname == NULL) {
1025 goto out;
1028 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
1029 new_jobname);
1032 * add any options defined in smb.conf
1035 if (!push_utf8_talloc(frame, &cupsoptions, lp_cups_options(snum), &size)) {
1036 goto out;
1038 num_options = 0;
1039 options = NULL;
1040 num_options = cupsParseOptions(cupsoptions, num_options, &options);
1042 if ( num_options )
1043 cupsEncodeOptions(request, num_options, options);
1046 * Do the request and get back a response...
1049 slprintf(uri, sizeof(uri) - 1, "/printers/%s", printername);
1051 if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
1052 goto out;
1054 if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
1055 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1056 DEBUG(0,("Unable to print file to %s - %s\n",
1057 lp_printername(snum),
1058 ippErrorString(cupsLastError())));
1059 } else {
1060 ret = 0;
1061 attr_job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
1062 if(attr_job_id) {
1063 pjob->sysjob = attr_job_id->values[0].integer;
1064 DEBUG(5,("cups_job_submit: job-id %d\n", pjob->sysjob));
1065 } else {
1066 DEBUG(0,("Missing job-id attribute in IPP response"));
1069 } else {
1070 DEBUG(0,("Unable to print file to `%s' - %s\n",
1071 lp_printername(snum),
1072 ippErrorString(cupsLastError())));
1075 if ( ret == 0 )
1076 unlink(pjob->filename);
1077 /* else print_job_end will do it for us */
1079 out:
1080 if (response)
1081 ippDelete(response);
1083 if (language)
1084 cupsLangFree(language);
1086 if (http)
1087 httpClose(http);
1089 TALLOC_FREE(frame);
1091 return ret;
1095 * 'cups_queue_get()' - Get all the jobs in the print queue.
1098 static int cups_queue_get(const char *sharename,
1099 enum printing_types printing_type,
1100 char *lpq_command,
1101 print_queue_struct **q,
1102 print_status_struct *status)
1104 TALLOC_CTX *frame = talloc_stackframe();
1105 char *printername = NULL;
1106 http_t *http = NULL; /* HTTP connection to server */
1107 ipp_t *request = NULL, /* IPP Request */
1108 *response = NULL; /* IPP Response */
1109 ipp_attribute_t *attr = NULL; /* Current attribute */
1110 cups_lang_t *language = NULL; /* Default language */
1111 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1112 int qcount = 0, /* Number of active queue entries */
1113 qalloc = 0; /* Number of queue entries allocated */
1114 print_queue_struct *queue = NULL, /* Queue entries */
1115 *temp; /* Temporary pointer for queue */
1116 char *user_name = NULL, /* job-originating-user-name attribute */
1117 *job_name = NULL; /* job-name attribute */
1118 int job_id; /* job-id attribute */
1119 int job_k_octets; /* job-k-octets attribute */
1120 time_t job_time; /* time-at-creation attribute */
1121 ipp_jstate_t job_status; /* job-status attribute */
1122 int job_priority; /* job-priority attribute */
1123 size_t size;
1124 static const char *jattrs[] = /* Requested job attributes */
1126 "job-id",
1127 "job-k-octets",
1128 "job-name",
1129 "job-originating-user-name",
1130 "job-priority",
1131 "job-state",
1132 "time-at-creation",
1134 static const char *pattrs[] = /* Requested printer attributes */
1136 "printer-state",
1137 "printer-state-message"
1140 *q = NULL;
1142 /* HACK ALERT!!! The problem with support the 'printer name'
1143 option is that we key the tdb off the sharename. So we will
1144 overload the lpq_command string to pass in the printername
1145 (which is basically what we do for non-cups printers ... using
1146 the lpq_command to get the queue listing). */
1148 if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1149 goto out;
1151 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1154 * Make sure we don't ask for passwords...
1157 cupsSetPasswordCB(cups_passwd_cb);
1160 * Try to connect to the server...
1163 if ((http = cups_connect(frame)) == NULL) {
1164 goto out;
1168 * Generate the printer URI...
1171 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s", printername);
1174 * Build an IPP_GET_JOBS request, which requires the following
1175 * attributes:
1177 * attributes-charset
1178 * attributes-natural-language
1179 * requested-attributes
1180 * printer-uri
1183 request = ippNew();
1185 request->request.op.operation_id = IPP_GET_JOBS;
1186 request->request.op.request_id = 1;
1188 language = cupsLangDefault();
1190 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1191 "attributes-charset", NULL, "utf-8");
1193 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1194 "attributes-natural-language", NULL, language->language);
1196 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1197 "requested-attributes",
1198 (sizeof(jattrs) / sizeof(jattrs[0])),
1199 NULL, jattrs);
1201 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1202 "printer-uri", NULL, uri);
1205 * Do the request and get back a response...
1208 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1209 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1210 ippErrorString(cupsLastError())));
1211 goto out;
1214 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1215 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1216 ippErrorString(response->request.status.status_code)));
1217 goto out;
1221 * Process the jobs...
1224 qcount = 0;
1225 qalloc = 0;
1226 queue = NULL;
1228 for (attr = response->attrs; attr != NULL; attr = attr->next) {
1230 * Skip leading attributes until we hit a job...
1233 while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1234 attr = attr->next;
1236 if (attr == NULL)
1237 break;
1240 * Allocate memory as needed...
1242 if (qcount >= qalloc) {
1243 qalloc += 16;
1245 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1247 if (queue == NULL) {
1248 DEBUG(0,("cups_queue_get: Not enough memory!"));
1249 qcount = 0;
1250 goto out;
1254 temp = queue + qcount;
1255 memset(temp, 0, sizeof(print_queue_struct));
1258 * Pull the needed attributes from this job...
1261 job_id = 0;
1262 job_priority = 50;
1263 job_status = IPP_JOB_PENDING;
1264 job_time = 0;
1265 job_k_octets = 0;
1266 user_name = NULL;
1267 job_name = NULL;
1269 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) {
1270 if (attr->name == NULL) {
1271 attr = attr->next;
1272 break;
1275 if (strcmp(attr->name, "job-id") == 0 &&
1276 attr->value_tag == IPP_TAG_INTEGER)
1277 job_id = attr->values[0].integer;
1279 if (strcmp(attr->name, "job-k-octets") == 0 &&
1280 attr->value_tag == IPP_TAG_INTEGER)
1281 job_k_octets = attr->values[0].integer;
1283 if (strcmp(attr->name, "job-priority") == 0 &&
1284 attr->value_tag == IPP_TAG_INTEGER)
1285 job_priority = attr->values[0].integer;
1287 if (strcmp(attr->name, "job-state") == 0 &&
1288 attr->value_tag == IPP_TAG_ENUM)
1289 job_status = (ipp_jstate_t)(attr->values[0].integer);
1291 if (strcmp(attr->name, "time-at-creation") == 0 &&
1292 attr->value_tag == IPP_TAG_INTEGER)
1293 job_time = attr->values[0].integer;
1295 if (strcmp(attr->name, "job-name") == 0 &&
1296 attr->value_tag == IPP_TAG_NAME) {
1297 if (!pull_utf8_talloc(frame,
1298 &job_name,
1299 attr->values[0].string.text,
1300 &size)) {
1301 goto out;
1305 if (strcmp(attr->name, "job-originating-user-name") == 0 &&
1306 attr->value_tag == IPP_TAG_NAME) {
1307 if (!pull_utf8_talloc(frame,
1308 &user_name,
1309 attr->values[0].string.text,
1310 &size)) {
1311 goto out;
1315 attr = attr->next;
1319 * See if we have everything needed...
1322 if (user_name == NULL || job_name == NULL || job_id == 0) {
1323 if (attr == NULL)
1324 break;
1325 else
1326 continue;
1329 temp->job = job_id;
1330 temp->size = job_k_octets * 1024;
1331 temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1332 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1333 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1334 LPQ_PRINTING;
1335 temp->priority = job_priority;
1336 temp->time = job_time;
1337 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1338 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1340 qcount ++;
1342 if (attr == NULL)
1343 break;
1346 ippDelete(response);
1347 response = NULL;
1350 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1351 * following attributes:
1353 * attributes-charset
1354 * attributes-natural-language
1355 * requested-attributes
1356 * printer-uri
1359 request = ippNew();
1361 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1362 request->request.op.request_id = 1;
1364 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1365 "attributes-charset", NULL, "utf-8");
1367 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1368 "attributes-natural-language", NULL, language->language);
1370 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1371 "requested-attributes",
1372 (sizeof(pattrs) / sizeof(pattrs[0])),
1373 NULL, pattrs);
1375 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1376 "printer-uri", NULL, uri);
1379 * Do the request and get back a response...
1382 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1383 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1384 ippErrorString(cupsLastError())));
1385 goto out;
1388 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1389 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1390 ippErrorString(response->request.status.status_code)));
1391 goto out;
1395 * Get the current printer status and convert it to the SAMBA values.
1398 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1399 if (attr->values[0].integer == IPP_PRINTER_STOPPED)
1400 status->status = LPSTAT_STOPPED;
1401 else
1402 status->status = LPSTAT_OK;
1405 if ((attr = ippFindAttribute(response, "printer-state-message",
1406 IPP_TAG_TEXT)) != NULL) {
1407 char *msg = NULL;
1408 if (!pull_utf8_talloc(frame, &msg,
1409 attr->values[0].string.text,
1410 &size)) {
1411 SAFE_FREE(queue);
1412 qcount = 0;
1413 goto out;
1415 fstrcpy(status->message, msg);
1418 out:
1421 * Return the job queue...
1424 *q = queue;
1426 if (response)
1427 ippDelete(response);
1429 if (language)
1430 cupsLangFree(language);
1432 if (http)
1433 httpClose(http);
1435 TALLOC_FREE(frame);
1436 return qcount;
1441 * 'cups_queue_pause()' - Pause a print queue.
1444 static int cups_queue_pause(int snum)
1446 TALLOC_CTX *frame = talloc_stackframe();
1447 int ret = 1; /* Return value */
1448 http_t *http = NULL; /* HTTP connection to server */
1449 ipp_t *request = NULL, /* IPP Request */
1450 *response = NULL; /* IPP Response */
1451 cups_lang_t *language = NULL; /* Default language */
1452 char *printername = NULL;
1453 char *username = NULL;
1454 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1455 size_t size;
1457 DEBUG(5,("cups_queue_pause(%d)\n", snum));
1460 * Make sure we don't ask for passwords...
1463 cupsSetPasswordCB(cups_passwd_cb);
1466 * Try to connect to the server...
1469 if ((http = cups_connect(frame)) == NULL) {
1470 goto out;
1474 * Build an IPP_PAUSE_PRINTER request, which requires the following
1475 * attributes:
1477 * attributes-charset
1478 * attributes-natural-language
1479 * printer-uri
1480 * requesting-user-name
1483 request = ippNew();
1485 request->request.op.operation_id = IPP_PAUSE_PRINTER;
1486 request->request.op.request_id = 1;
1488 language = cupsLangDefault();
1490 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1491 "attributes-charset", NULL, "utf-8");
1493 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1494 "attributes-natural-language", NULL, language->language);
1496 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1497 &size)) {
1498 goto out;
1500 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1501 printername);
1503 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1505 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1506 goto out;
1508 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1509 NULL, username);
1512 * Do the request and get back a response...
1515 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1516 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1517 DEBUG(0,("Unable to pause printer %s - %s\n",
1518 lp_printername(snum),
1519 ippErrorString(cupsLastError())));
1520 } else {
1521 ret = 0;
1523 } else {
1524 DEBUG(0,("Unable to pause printer %s - %s\n",
1525 lp_printername(snum),
1526 ippErrorString(cupsLastError())));
1529 out:
1530 if (response)
1531 ippDelete(response);
1533 if (language)
1534 cupsLangFree(language);
1536 if (http)
1537 httpClose(http);
1539 TALLOC_FREE(frame);
1540 return ret;
1545 * 'cups_queue_resume()' - Restart a print queue.
1548 static int cups_queue_resume(int snum)
1550 TALLOC_CTX *frame = talloc_stackframe();
1551 int ret = 1; /* Return value */
1552 http_t *http = NULL; /* HTTP connection to server */
1553 ipp_t *request = NULL, /* IPP Request */
1554 *response = NULL; /* IPP Response */
1555 cups_lang_t *language = NULL; /* Default language */
1556 char *printername = NULL;
1557 char *username = NULL;
1558 char uri[HTTP_MAX_URI]; /* printer-uri attribute */
1559 size_t size;
1561 DEBUG(5,("cups_queue_resume(%d)\n", snum));
1564 * Make sure we don't ask for passwords...
1567 cupsSetPasswordCB(cups_passwd_cb);
1570 * Try to connect to the server...
1573 if ((http = cups_connect(frame)) == NULL) {
1574 goto out;
1578 * Build an IPP_RESUME_PRINTER request, which requires the following
1579 * attributes:
1581 * attributes-charset
1582 * attributes-natural-language
1583 * printer-uri
1584 * requesting-user-name
1587 request = ippNew();
1589 request->request.op.operation_id = IPP_RESUME_PRINTER;
1590 request->request.op.request_id = 1;
1592 language = cupsLangDefault();
1594 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1595 "attributes-charset", NULL, "utf-8");
1597 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1598 "attributes-natural-language", NULL, language->language);
1600 if (!push_utf8_talloc(frame, &printername, lp_printername(snum),
1601 &size)) {
1602 goto out;
1604 slprintf(uri, sizeof(uri) - 1, "ipp://localhost/printers/%s",
1605 printername);
1607 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1609 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1610 goto out;
1612 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1613 NULL, username);
1616 * Do the request and get back a response...
1619 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1620 if (response->request.status.status_code >= IPP_OK_CONFLICT) {
1621 DEBUG(0,("Unable to resume printer %s - %s\n",
1622 lp_printername(snum),
1623 ippErrorString(cupsLastError())));
1624 } else {
1625 ret = 0;
1627 } else {
1628 DEBUG(0,("Unable to resume printer %s - %s\n",
1629 lp_printername(snum),
1630 ippErrorString(cupsLastError())));
1633 out:
1634 if (response)
1635 ippDelete(response);
1637 if (language)
1638 cupsLangFree(language);
1640 if (http)
1641 httpClose(http);
1643 TALLOC_FREE(frame);
1644 return ret;
1647 /*******************************************************************
1648 * CUPS printing interface definitions...
1649 ******************************************************************/
1651 struct printif cups_printif =
1653 PRINT_CUPS,
1654 cups_queue_get,
1655 cups_queue_pause,
1656 cups_queue_resume,
1657 cups_job_delete,
1658 cups_job_pause,
1659 cups_job_resume,
1660 cups_job_submit,
1663 bool cups_pull_comment_location(TALLOC_CTX *mem_ctx,
1664 const char *printername,
1665 char **comment,
1666 char **location)
1668 TALLOC_CTX *frame = talloc_stackframe();
1669 http_t *http = NULL; /* HTTP connection to server */
1670 ipp_t *request = NULL, /* IPP Request */
1671 *response = NULL; /* IPP Response */
1672 ipp_attribute_t *attr; /* Current attribute */
1673 cups_lang_t *language = NULL; /* Default language */
1674 char uri[HTTP_MAX_URI];
1675 char *server = NULL;
1676 char *sharename = NULL;
1677 char *name = NULL;
1678 static const char *requested[] =/* Requested attributes */
1680 "printer-name",
1681 "printer-info",
1682 "printer-location"
1684 bool ret = False;
1685 size_t size;
1687 DEBUG(5, ("pulling %s location\n", printername));
1690 * Make sure we don't ask for passwords...
1693 cupsSetPasswordCB(cups_passwd_cb);
1696 * Try to connect to the server...
1699 if ((http = cups_connect(frame)) == NULL) {
1700 goto out;
1703 request = ippNew();
1705 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
1706 request->request.op.request_id = 1;
1708 language = cupsLangDefault();
1710 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1711 "attributes-charset", NULL, "utf-8");
1713 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1714 "attributes-natural-language", NULL, language->language);
1716 if (lp_cups_server() != NULL && strlen(lp_cups_server()) > 0) {
1717 if (!push_utf8_talloc(frame, &server, lp_cups_server(), &size)) {
1718 goto out;
1720 } else {
1721 server = talloc_strdup(frame,cupsServer());
1723 if (server) {
1724 goto out;
1726 if (!push_utf8_talloc(frame, &sharename, printername, &size)) {
1727 goto out;
1729 slprintf(uri, sizeof(uri) - 1, "ipp://%s/printers/%s",
1730 server, sharename);
1732 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1733 "printer-uri", NULL, uri);
1735 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1736 "requested-attributes",
1737 (sizeof(requested) / sizeof(requested[0])),
1738 NULL, requested);
1741 * Do the request and get back a response...
1744 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1745 DEBUG(0,("Unable to get printer attributes - %s\n",
1746 ippErrorString(cupsLastError())));
1747 goto out;
1750 for (attr = response->attrs; attr != NULL;) {
1752 * Skip leading attributes until we hit a printer...
1755 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1756 attr = attr->next;
1758 if (attr == NULL)
1759 break;
1762 * Pull the needed attributes from this printer...
1765 while ( attr && (attr->group_tag == IPP_TAG_PRINTER) ) {
1766 if (strcmp(attr->name, "printer-name") == 0 &&
1767 attr->value_tag == IPP_TAG_NAME) {
1768 if (!pull_utf8_talloc(frame,
1769 &name,
1770 attr->values[0].string.text,
1771 &size)) {
1772 goto out;
1776 /* Grab the comment if we don't have one */
1777 if ( (strcmp(attr->name, "printer-info") == 0)
1778 && (attr->value_tag == IPP_TAG_TEXT))
1780 if (!pull_utf8_talloc(mem_ctx,
1781 comment,
1782 attr->values[0].string.text,
1783 &size)) {
1784 goto out;
1786 DEBUG(5,("cups_pull_comment_location: Using cups comment: %s\n",
1787 *comment));
1790 /* Grab the location if we don't have one */
1791 if ( (strcmp(attr->name, "printer-location") == 0)
1792 && (attr->value_tag == IPP_TAG_TEXT))
1794 if (!pull_utf8_talloc(mem_ctx,
1795 location,
1796 attr->values[0].string.text,
1797 &size)) {
1798 goto out;
1800 DEBUG(5,("cups_pull_comment_location: Using cups location: %s\n",
1801 *location));
1804 attr = attr->next;
1808 * We have everything needed...
1811 if (name != NULL)
1812 break;
1815 ret = True;
1817 out:
1818 if (response)
1819 ippDelete(response);
1821 if (request) {
1822 ippDelete(request);
1825 if (language)
1826 cupsLangFree(language);
1828 if (http)
1829 httpClose(http);
1831 TALLOC_FREE(frame);
1832 return ret;
1835 #else
1836 /* this keeps fussy compilers happy */
1837 void print_cups_dummy(void);
1838 void print_cups_dummy(void) {}
1839 #endif /* HAVE_CUPS */