1 /*
2 * Support code for the Common UNIX Printing System ("CUPS")
3 *
4 * Copyright 1999-2003 by Michael R Sweet.
5 * Copyright 2008 Jeremy Allison.
6 *
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.
11 *
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.
16 *
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/>.
19 */
20
21 /*
22 * JRA. Converted to utf8 pull/push.
23 */
24
25 #include "includes.h"
26 #include "printing.h"
27 #include "printing/pcap.h"
28 #include "librpc/gen_ndr/ndr_printcap.h"
29 #include "lib/util/sys_rw.h"
30
31 #ifdef HAVE_CUPS
aix_cache_reload(struct pcap_cache ** _pcache)32 #include <cups/cups.h>
33 #include <cups/language.h>
34 #include <cups/http.h>
35
36 /* CUPS prior to version 1.7 doesn't have HTTP_URI_STATUS_OK */
37 #if (CUPS_VERSION_MAJOR == 1) && (CUPS_VERSION_MINOR < 7)
38 #define HTTP_URI_STATUS_OK HTTP_URI_OK
39 #endif
40
41 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
42 #define HAVE_CUPS_1_6 1
43 #endif
44
45 #ifndef HAVE_CUPS_1_6
46 #define ippGetGroupTag(attr) attr->group_tag
47 #define ippGetName(attr) attr->name
48 #define ippGetValueTag(attr) attr->value_tag
49 #define ippGetStatusCode(ipp) ipp->request.status.status_code
50 #define ippGetInteger(attr, element) attr->values[element].integer
51 #define ippGetString(attr, element, language) attr->values[element].string.text
52
53 static ipp_attribute_t *
54 ippFirstAttribute(ipp_t *ipp)
55 {
56 if (!ipp)
57 return (NULL);
58 return (ipp->current = ipp->attrs);
59 }
60
61 static ipp_attribute_t *
62 ippNextAttribute(ipp_t *ipp)
63 {
64 if (!ipp || !ipp->current)
65 return (NULL);
66 return (ipp->current = ipp->current->next);
67 }
68
69 static int ippSetOperation(ipp_t *ipp, ipp_op_t op)
70 {
71 ipp->request.op.operation_id = op;
72 return (1);
73 }
74
75 static int ippSetRequestId(ipp_t *ipp, int request_id)
76 {
77 ipp->request.any.request_id = request_id;
78 return (1);
79 }
80 #endif
81
82 static SIG_ATOMIC_T gotalarm;
83
84 /***************************************************************
85 Signal function to tell us we timed out.
86 ****************************************************************/
87
88 static void gotalarm_sig(int signum)
89 {
90 gotalarm = 1;
91 }
92
93 extern userdom_struct current_user_info;
94
95 /*
96 * 'cups_passwd_cb()' - The CUPS password callback...
97 */
98
99 static const char * /* O - Password or NULL */
100 cups_passwd_cb(const char *prompt) /* I - Prompt */
101 {
102 /*
103 * Always return NULL to indicate that no password is available...
104 */
105
106 return (NULL);
107 }
108
109 static http_t *cups_connect(TALLOC_CTX *frame)
110 {
111 const struct loadparm_substitution *lp_sub =
112 loadparm_s3_global_substitution();
113 http_t *http = NULL;
114 char *server = NULL, *p = NULL;
115 int port;
116 int timeout = lp_cups_connection_timeout();
117 size_t size;
118
119 if (lp_cups_server(talloc_tos(), lp_sub) != NULL && strlen(lp_cups_server(talloc_tos(), lp_sub)) > 0) {
120 if (!push_utf8_talloc(frame, &server, lp_cups_server(talloc_tos(), lp_sub), &size)) {
121 return NULL;
122 }
123 } else {
124 server = talloc_strdup(frame,cupsServer());
125 }
126 if (!server) {
127 return NULL;
128 }
129
130 p = strchr(server, ':');
131 if (p) {
132 port = atoi(p+1);
133 *p = '\0';
134 } else {
135 port = ippPort();
136 }
137
138 DEBUG(10, ("connecting to cups server %s:%d\n",
print_aix_dummy(void)139 server, port));
140
141 gotalarm = 0;
142
143 if (timeout) {
144 CatchSignal(SIGALRM, gotalarm_sig);
145 alarm(timeout);
146 }
147
148 #if defined(HAVE_HTTPCONNECT2)
149 http = httpConnect2(server,
150 port,
151 NULL,
152 AF_UNSPEC,
153 lp_cups_encrypt() ?
154 HTTP_ENCRYPTION_ALWAYS :
155 HTTP_ENCRYPTION_IF_REQUESTED,
156 1, /* blocking */
157 30 * 1000, /* timeout */
158 NULL);
159 #elif defined(HAVE_HTTPCONNECTENCRYPT)
160 http = httpConnectEncrypt(server, port, lp_cups_encrypt());
161 #else
162 http = httpConnect(server, port);
163 #endif
164
165
166 CatchSignal(SIGALRM, SIG_IGN);
167 alarm(0);
168
169 if (http == NULL) {
170 DEBUG(3,("Unable to connect to CUPS server %s:%d - %s\n",
171 server, port, strerror(errno)));
172 }
173
174 return http;
175 }
176
177 static bool send_pcap_blob(DATA_BLOB *pcap_blob, int fd)
178 {
179 size_t ret;
180
181 ret = sys_write(fd, &pcap_blob->length, sizeof(pcap_blob->length));
182 if (ret != sizeof(pcap_blob->length)) {
183 return false;
184 }
185
186 ret = sys_write(fd, pcap_blob->data, pcap_blob->length);
187 if (ret != pcap_blob->length) {
188 return false;
189 }
190
191 DEBUG(10, ("successfully sent blob of len %d\n", (int)ret));
192 return true;
193 }
194
195 static bool recv_pcap_blob(TALLOC_CTX *mem_ctx, int fd, DATA_BLOB *pcap_blob)
196 {
197 size_t blob_len;
198 size_t ret;
199
200 ret = sys_read(fd, &blob_len, sizeof(blob_len));
201 if (ret != sizeof(blob_len)) {
202 return false;
203 }
204
205 *pcap_blob = data_blob_talloc_named(mem_ctx, NULL, blob_len,
206 "cups pcap");
207 if (pcap_blob->length != blob_len) {
208 return false;
209 }
210 ret = sys_read(fd, pcap_blob->data, blob_len);
211 if (ret != blob_len) {
212 talloc_free(pcap_blob->data);
213 return false;
214 }
215
216 DEBUG(10, ("successfully recvd blob of len %d\n", (int)ret));
217 return true;
218 }
219
220 static bool process_cups_printers_response(TALLOC_CTX *mem_ctx,
221 ipp_t *response,
222 struct pcap_data *pcap_data)
223 {
224 ipp_attribute_t *attr;
225 char *name;
226 char *info;
227 char *location = NULL;
228 struct pcap_printer *printer;
229 bool ret_ok = false;
230
231 for (attr = ippFirstAttribute(response); attr != NULL;) {
232 /*
233 * Skip leading attributes until we hit a printer...
234 */
235
236 while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_PRINTER)
237 attr = ippNextAttribute(response);
238
239 if (attr == NULL)
240 break;
241
242 /*
243 * Pull the needed attributes from this printer...
244 */
245
246 name = NULL;
247 info = NULL;
248
249 while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_PRINTER) {
250 size_t size;
251 if (strcmp(ippGetName(attr), "printer-name") == 0 &&
252 ippGetValueTag(attr) == IPP_TAG_NAME) {
253 if (!pull_utf8_talloc(mem_ctx,
254 &name,
255 ippGetString(attr, 0, NULL),
256 &size)) {
257 goto err_out;
258 }
259 }
260
261 if (strcmp(ippGetName(attr), "printer-info") == 0 &&
262 ippGetValueTag(attr) == IPP_TAG_TEXT) {
263 if (!pull_utf8_talloc(mem_ctx,
264 &info,
265 ippGetString(attr, 0, NULL),
266 &size)) {
267 goto err_out;
268 }
269 }
270
271 if (strcmp(ippGetName(attr), "printer-location") == 0 &&
272 ippGetValueTag(attr) == IPP_TAG_TEXT) {
273 if (!pull_utf8_talloc(mem_ctx,
274 &location,
275 ippGetString(attr, 0, NULL),
276 &size)) {
277 goto err_out;
278 }
279 }
280
281 attr = ippNextAttribute(response);
282 }
283
284 /*
285 * See if we have everything needed...
286 */
287
288 if (name == NULL)
289 break;
290
291 if (pcap_data->count == 0) {
292 printer = talloc_array(mem_ctx, struct pcap_printer, 1);
293 } else {
294 printer = talloc_realloc(mem_ctx, pcap_data->printers,
295 struct pcap_printer,
296 pcap_data->count + 1);
297 }
298 if (printer == NULL) {
299 goto err_out;
300 }
301 pcap_data->printers = printer;
302 pcap_data->printers[pcap_data->count].name = name;
303 pcap_data->printers[pcap_data->count].info = info;
304 pcap_data->printers[pcap_data->count].location = location;
305 pcap_data->count++;
306 }
307
308 ret_ok = true;
309 err_out:
310 return ret_ok;
311 }
312
313 /*
314 * request printer list from cups, send result back to up parent via fd.
315 * returns true if the (possibly failed) result was successfully sent to parent.
316 */
317 static bool cups_cache_reload_async(int fd)
318 {
319 TALLOC_CTX *frame = talloc_stackframe();
320 struct pcap_data pcap_data;
321 http_t *http = NULL; /* HTTP connection to server */
322 ipp_t *request = NULL, /* IPP Request */
323 *response = NULL; /* IPP Response */
324 cups_lang_t *language = NULL; /* Default language */
325 static const char *requested[] =/* Requested attributes */
326 {
327 "printer-name",
328 "printer-info",
329 "printer-location"
330 };
331 bool ret = False;
332 enum ndr_err_code ndr_ret;
333 DATA_BLOB pcap_blob;
334
335 ZERO_STRUCT(pcap_data);
336 pcap_data.status = NT_STATUS_UNSUCCESSFUL;
337
338 DEBUG(5, ("reloading cups printcap cache\n"));
339
340 /*
341 * Make sure we don't ask for passwords...
342 */
343
344 cupsSetPasswordCB(cups_passwd_cb);
345
346 if ((http = cups_connect(frame)) == NULL) {
347 goto out;
348 }
349
350 /*
351 * Build a CUPS_GET_PRINTERS request, which requires the following
352 * attributes:
353 *
354 * attributes-charset
355 * attributes-natural-language
356 * requested-attributes
357 */
358
359 request = ippNew();
360
361 ippSetOperation(request, CUPS_GET_PRINTERS);
362 ippSetRequestId(request, 1);
363
364 language = cupsLangDefault();
365
366 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
367 "attributes-charset", NULL, "utf-8");
368
369 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
370 "attributes-natural-language", NULL, language->language);
371
372 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
373 "requested-attributes",
374 (sizeof(requested) / sizeof(requested[0])),
375 NULL, requested);
376
377 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
378 DEBUG(0,("Unable to get printer list - %s\n",
379 ippErrorString(cupsLastError())));
380 goto out;
381 }
382
383 ret = process_cups_printers_response(frame, response, &pcap_data);
384 if (!ret) {
385 DEBUG(0,("failed to process cups response\n"));
386 goto out;
387 }
388
389 ippDelete(response);
390 response = NULL;
391
392 /*
393 * Build a CUPS_GET_CLASSES request, which requires the following
394 * attributes:
395 *
396 * attributes-charset
397 * attributes-natural-language
398 * requested-attributes
399 */
400
401 request = ippNew();
402
403 ippSetOperation(request, CUPS_GET_CLASSES);
404 ippSetRequestId(request, 1);
405
406 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
407 "attributes-charset", NULL, "utf-8");
408
409 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
410 "attributes-natural-language", NULL, language->language);
411
412 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
413 "requested-attributes",
414 (sizeof(requested) / sizeof(requested[0])),
415 NULL, requested);
416
417 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
418 DEBUG(0,("Unable to get printer list - %s\n",
419 ippErrorString(cupsLastError())));
420 goto out;
421 }
422
423 ret = process_cups_printers_response(frame, response, &pcap_data);
424 if (!ret) {
425 DEBUG(0,("failed to process cups response\n"));
426 goto out;
427 }
428
429 pcap_data.status = NT_STATUS_OK;
430 out:
431 if (response)
432 ippDelete(response);
433
434 if (language)
435 cupsLangFree(language);
436
437 if (http)
438 httpClose(http);
439
440 ret = false;
441 ndr_ret = ndr_push_struct_blob(&pcap_blob, frame, &pcap_data,
442 (ndr_push_flags_fn_t)ndr_push_pcap_data);
443 if (ndr_ret == NDR_ERR_SUCCESS) {
444 ret = send_pcap_blob(&pcap_blob, fd);
445 }
446
447 TALLOC_FREE(frame);
448 return ret;
449 }
450
451 static struct tevent_fd *cache_fd_event;
452
453 static bool cups_pcap_load_async(struct tevent_context *ev,
454 struct messaging_context *msg_ctx,
455 int *pfd)
456 {
457 int fds[2];
458 pid_t pid;
459 NTSTATUS status;
460
461 *pfd = -1;
462
463 if (cache_fd_event) {
464 DEBUG(3,("cups_pcap_load_async: already waiting for "
465 "a refresh event\n" ));
466 return false;
467 }
468
469 DEBUG(5,("cups_pcap_load_async: asynchronously loading cups printers\n"));
470
471 if (pipe(fds) == -1) {
472 return false;
473 }
474
475 pid = fork();
476 if (pid == (pid_t)-1) {
477 DEBUG(10,("cups_pcap_load_async: fork failed %s\n",
478 strerror(errno) ));
479 close(fds[0]);
480 close(fds[1]);
481 return false;
482 }
483
484 if (pid) {
485 DEBUG(10,("cups_pcap_load_async: child pid = %u\n",
486 (unsigned int)pid ));
487 /* Parent. */
488 close(fds[1]);
489 *pfd = fds[0];
490 return true;
491 }
492
493 /* Child. */
494
495 close_all_print_db();
496
497 status = reinit_after_fork(msg_ctx, ev, true, NULL);
498 if (!NT_STATUS_IS_OK(status)) {
499 DEBUG(0,("cups_pcap_load_async: reinit_after_fork() failed\n"));
500 smb_panic("cups_pcap_load_async: reinit_after_fork() failed");
501 }
502
503 close(fds[0]);
504 cups_cache_reload_async(fds[1]);
505 close(fds[1]);
506 TALLOC_FREE(msg_ctx);
507 _exit(0);
508 }
509
510 struct cups_async_cb_args {
511 int pipe_fd;
512 struct tevent_context *event_ctx;
513 struct messaging_context *msg_ctx;
514 void (*post_cache_fill_fn)(struct tevent_context *,
515 struct messaging_context *);
516 };
517
518 static void cups_async_callback(struct tevent_context *event_ctx,
519 struct tevent_fd *event,
520 uint16_t flags,
521 void *p)
522 {
523 TALLOC_CTX *frame = talloc_stackframe();
524 struct cups_async_cb_args *cb_args = (struct cups_async_cb_args *)p;
525 struct pcap_cache *tmp_pcap_cache = NULL;
526 bool ret_ok;
527 struct pcap_data pcap_data;
528 DATA_BLOB pcap_blob;
529 enum ndr_err_code ndr_ret;
530 uint32_t i;
531
532 DEBUG(5,("cups_async_callback: callback received for printer data. "
533 "fd = %d\n", cb_args->pipe_fd));
534
535 ret_ok = recv_pcap_blob(frame, cb_args->pipe_fd, &pcap_blob);
536 if (!ret_ok) {
537 DEBUG(0,("failed to recv pcap blob\n"));
538 goto err_out;
539 }
540
541 ndr_ret = ndr_pull_struct_blob(&pcap_blob, frame, &pcap_data,
542 (ndr_pull_flags_fn_t)ndr_pull_pcap_data);
543 if (ndr_ret != NDR_ERR_SUCCESS) {
544 goto err_out;
545 }
546
547 if (!NT_STATUS_IS_OK(pcap_data.status)) {
548 DEBUG(3,("failed to retrieve printer list: %s\n",
549 nt_errstr(pcap_data.status)));
550 goto err_out;
551 }
552
553 for (i = 0; i < pcap_data.count; i++) {
554 ret_ok = pcap_cache_add_specific(&tmp_pcap_cache,
555 pcap_data.printers[i].name,
556 pcap_data.printers[i].info,
557 pcap_data.printers[i].location);
558 if (!ret_ok) {
559 DEBUG(0, ("failed to add to tmp pcap cache\n"));
560 goto err_out;
561 }
562 }
563
564 /* replace the system-wide pcap cache with a (possibly empty) new one */
565 ret_ok = pcap_cache_replace(tmp_pcap_cache);
566 if (!ret_ok) {
567 DEBUG(0, ("failed to replace pcap cache\n"));
568 } else if (cb_args->post_cache_fill_fn != NULL) {
569 /* Caller requested post cache fill callback */
570 cb_args->post_cache_fill_fn(cb_args->event_ctx,
571 cb_args->msg_ctx);
572 }
573 err_out:
574 pcap_cache_destroy_specific(&tmp_pcap_cache);
575 TALLOC_FREE(frame);
576 TALLOC_FREE(cache_fd_event);
577 close(cb_args->pipe_fd);
578 TALLOC_FREE(cb_args);
579 }
580
581 bool cups_cache_reload(struct tevent_context *ev,
582 struct messaging_context *msg_ctx,
583 void (*post_cache_fill_fn)(struct tevent_context *,
584 struct messaging_context *))
585 {
586 struct cups_async_cb_args *cb_args;
587 int *p_pipe_fd;
588
589 cb_args = talloc(NULL, struct cups_async_cb_args);
590 if (cb_args == NULL) {
591 return false;
592 }
593
594 cb_args->post_cache_fill_fn = post_cache_fill_fn;
595 cb_args->event_ctx = ev;
596 cb_args->msg_ctx = msg_ctx;
597 p_pipe_fd = &cb_args->pipe_fd;
598 *p_pipe_fd = -1;
599
600 /* Set up an async refresh. */
601 if (!cups_pcap_load_async(ev, msg_ctx, p_pipe_fd)) {
602 talloc_free(cb_args);
603 return false;
604 }
605
606 DEBUG(10,("cups_cache_reload: async read on fd %d\n",
607 *p_pipe_fd ));
608
609 /* Trigger an event when the pipe can be read. */
610 cache_fd_event = tevent_add_fd(ev,
611 NULL, *p_pipe_fd,
612 TEVENT_FD_READ,
613 cups_async_callback,
614 (void *)cb_args);
615 if (!cache_fd_event) {
616 close(*p_pipe_fd);
617 TALLOC_FREE(cb_args);
618 return false;
619 }
620
621 return true;
622 }
623
624 /*
625 * 'cups_job_delete()' - Delete a job.
626 */
627
628 static int cups_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob)
629 {
630 TALLOC_CTX *frame = talloc_stackframe();
631 int ret = 1; /* Return value */
632 http_t *http = NULL; /* HTTP connection to server */
633 ipp_t *request = NULL, /* IPP Request */
634 *response = NULL; /* IPP Response */
635 cups_lang_t *language = NULL; /* Default language */
636 char *user = NULL;
637 char uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
638 http_uri_status_t ustatus;
639 size_t size;
640
641 DEBUG(5,("cups_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob));
642
643 /*
644 * Make sure we don't ask for passwords...
645 */
646
647 cupsSetPasswordCB(cups_passwd_cb);
648
649 /*
650 * Try to connect to the server...
651 */
652
653 if ((http = cups_connect(frame)) == NULL) {
654 goto out;
655 }
656
657 /*
658 * Build an IPP_CANCEL_JOB request, which requires the following
659 * attributes:
660 *
661 * attributes-charset
662 * attributes-natural-language
663 * job-uri
664 * requesting-user-name
665 */
666
667 request = ippNew();
668
669 ippSetOperation(request, IPP_CANCEL_JOB);
670 ippSetRequestId(request, 1);
671
672 language = cupsLangDefault();
673
674 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
675 "attributes-charset", NULL, "utf-8");
676
677 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
678 "attributes-natural-language", NULL, language->language);
679
680 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
681 uri,
682 sizeof(uri),
683 "ipp",
684 NULL, /* username */
685 "localhost",
686 ippPort(),
687 "/jobs/%d",
688 pjob->sysjob);
689 if (ustatus != HTTP_URI_STATUS_OK) {
690 goto out;
691 }
692
693 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
694
695 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
696 goto out;
697 }
698
699 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
700 NULL, user);
701
702 /*
703 * Do the request and get back a response...
704 */
705
706 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
707 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
708 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
709 ippErrorString(cupsLastError())));
710 } else {
711 ret = 0;
712 }
713 } else {
714 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob,
715 ippErrorString(cupsLastError())));
716 }
717
718 out:
719 if (response)
720 ippDelete(response);
721
722 if (language)
723 cupsLangFree(language);
724
725 if (http)
726 httpClose(http);
727
728 TALLOC_FREE(frame);
729 return ret;
730 }
731
732
733 /*
734 * 'cups_job_pause()' - Pause a job.
735 */
736
737 static int cups_job_pause(int snum, struct printjob *pjob)
738 {
739 TALLOC_CTX *frame = talloc_stackframe();
740 int ret = 1; /* Return value */
741 http_t *http = NULL; /* HTTP connection to server */
742 ipp_t *request = NULL, /* IPP Request */
743 *response = NULL; /* IPP Response */
744 cups_lang_t *language = NULL; /* Default language */
745 char *user = NULL;
746 char uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
747 http_uri_status_t ustatus;
748 size_t size;
749
750 DEBUG(5,("cups_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
751
752 /*
753 * Make sure we don't ask for passwords...
754 */
755
756 cupsSetPasswordCB(cups_passwd_cb);
757
758 /*
759 * Try to connect to the server...
760 */
761
762 if ((http = cups_connect(frame)) == NULL) {
763 goto out;
764 }
765
766 /*
767 * Build an IPP_HOLD_JOB request, which requires the following
768 * attributes:
769 *
770 * attributes-charset
771 * attributes-natural-language
772 * job-uri
773 * requesting-user-name
774 */
775
776 request = ippNew();
777
778 ippSetOperation(request, IPP_HOLD_JOB);
779 ippSetRequestId(request, 1);
780
781 language = cupsLangDefault();
782
783 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
784 "attributes-charset", NULL, "utf-8");
785
786 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
787 "attributes-natural-language", NULL, language->language);
788
789 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
790 uri,
791 sizeof(uri),
792 "ipp",
793 NULL, /* username */
794 "localhost",
795 ippPort(),
796 "/jobs/%d",
797 pjob->sysjob);
798 if (ustatus != HTTP_URI_STATUS_OK) {
799 goto out;
800 }
801
802 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
803
804 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
805 goto out;
806 }
807 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
808 NULL, user);
809
810 /*
811 * Do the request and get back a response...
812 */
813
814 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
815 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
816 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
817 ippErrorString(cupsLastError())));
818 } else {
819 ret = 0;
820 }
821 } else {
822 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob,
823 ippErrorString(cupsLastError())));
824 }
825
826 out:
827 if (response)
828 ippDelete(response);
829
830 if (language)
831 cupsLangFree(language);
832
833 if (http)
834 httpClose(http);
835
836 TALLOC_FREE(frame);
837 return ret;
838 }
839
840
841 /*
842 * 'cups_job_resume()' - Resume a paused job.
843 */
844
845 static int cups_job_resume(int snum, struct printjob *pjob)
846 {
847 TALLOC_CTX *frame = talloc_stackframe();
848 int ret = 1; /* Return value */
849 http_t *http = NULL; /* HTTP connection to server */
850 ipp_t *request = NULL, /* IPP Request */
851 *response = NULL; /* IPP Response */
852 cups_lang_t *language = NULL; /* Default language */
853 char *user = NULL;
854 char uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
855 http_uri_status_t ustatus;
856 size_t size;
857
858 DEBUG(5,("cups_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob));
859
860 /*
861 * Make sure we don't ask for passwords...
862 */
863
864 cupsSetPasswordCB(cups_passwd_cb);
865
866 /*
867 * Try to connect to the server...
868 */
869
870 if ((http = cups_connect(frame)) == NULL) {
871 goto out;
872 }
873
874 /*
875 * Build an IPP_RELEASE_JOB request, which requires the following
876 * attributes:
877 *
878 * attributes-charset
879 * attributes-natural-language
880 * job-uri
881 * requesting-user-name
882 */
883
884 request = ippNew();
885
886 ippSetOperation(request, IPP_RELEASE_JOB);
887 ippSetRequestId(request, 1);
888
889 language = cupsLangDefault();
890
891 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
892 "attributes-charset", NULL, "utf-8");
893
894 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
895 "attributes-natural-language", NULL, language->language);
896
897 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
898 uri,
899 sizeof(uri),
900 "ipp",
901 NULL, /* username */
902 "localhost",
903 ippPort(),
904 "/jobs/%d",
905 pjob->sysjob);
906 if (ustatus != HTTP_URI_STATUS_OK) {
907 goto out;
908 }
909
910 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
911
912 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
913 goto out;
914 }
915 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
916 NULL, user);
917
918 /*
919 * Do the request and get back a response...
920 */
921
922 if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) {
923 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
924 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
925 ippErrorString(cupsLastError())));
926 } else {
927 ret = 0;
928 }
929 } else {
930 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob,
931 ippErrorString(cupsLastError())));
932 }
933
934 out:
935 if (response)
936 ippDelete(response);
937
938 if (language)
939 cupsLangFree(language);
940
941 if (http)
942 httpClose(http);
943
944 TALLOC_FREE(frame);
945 return ret;
946 }
947
948
949 /*
950 * 'cups_job_submit()' - Submit a job for printing.
951 */
952
953 static int cups_job_submit(int snum, struct printjob *pjob,
954 enum printing_types printing_type,
955 char *lpq_cmd)
956 {
957 TALLOC_CTX *frame = talloc_stackframe();
958 const struct loadparm_substitution *lp_sub =
959 loadparm_s3_global_substitution();
960 int ret = 1; /* Return value */
961 http_t *http = NULL; /* HTTP connection to server */
962 ipp_t *request = NULL, /* IPP Request */
963 *response = NULL; /* IPP Response */
964 ipp_attribute_t *attr_job_id = NULL; /* IPP Attribute "job-id" */
965 cups_lang_t *language = NULL; /* Default language */
966 char uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
967 http_uri_status_t ustatus;
968 char *new_jobname = NULL;
969 int num_options = 0;
970 cups_option_t *options = NULL;
971 char *printername = NULL;
972 char *user = NULL;
973 char *jobname = NULL;
974 char *cupsoptions = NULL;
975 char *filename = NULL;
976 size_t size;
977
978 DEBUG(5,("cups_job_submit(%d, %p)\n", snum, pjob));
979
980 /*
981 * Make sure we don't ask for passwords...
982 */
983
984 cupsSetPasswordCB(cups_passwd_cb);
985
986 /*
987 * Try to connect to the server...
988 */
989
990 if ((http = cups_connect(frame)) == NULL) {
991 goto out;
992 }
993
994 /*
995 * Build an IPP_PRINT_JOB request, which requires the following
996 * attributes:
997 *
998 * attributes-charset
999 * attributes-natural-language
1000 * printer-uri
1001 * requesting-user-name
1002 * [document-data]
1003 */
1004
1005 request = ippNew();
1006
1007 ippSetOperation(request, IPP_PRINT_JOB);
1008 ippSetRequestId(request, 1);
1009
1010 language = cupsLangDefault();
1011
1012 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1013 "attributes-charset", NULL, "utf-8");
1014
1015 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1016 "attributes-natural-language", NULL, language->language);
1017
1018 if (!push_utf8_talloc(frame, &printername,
1019 lp_printername(talloc_tos(), lp_sub, snum),
1020 &size)) {
1021 goto out;
1022 }
1023 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1024 uri,
1025 sizeof(uri),
1026 "ipp",
1027 NULL, /* username */
1028 "localhost",
1029 ippPort(),
1030 "/printers/%s",
1031 printername);
1032 if (ustatus != HTTP_URI_STATUS_OK) {
1033 goto out;
1034 }
1035
1036 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1037 "printer-uri", NULL, uri);
1038
1039 if (!push_utf8_talloc(frame, &user, pjob->user, &size)) {
1040 goto out;
1041 }
1042 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1043 NULL, user);
1044
1045 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1046 "job-originating-host-name", NULL,
1047 pjob->clientmachine);
1048
1049 if (!push_utf8_talloc(frame, &jobname, pjob->jobname, &size)) {
1050 goto out;
1051 }
1052 new_jobname = talloc_asprintf(frame,
1053 "%s%.8u %s", PRINT_SPOOL_PREFIX,
1054 pjob->jobid, jobname);
1055 if (new_jobname == NULL) {
1056 goto out;
1057 }
1058
1059 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
1060 new_jobname);
1061
1062 /*
1063 * add any options defined in smb.conf
1064 */
1065
1066 if (!push_utf8_talloc(frame, &cupsoptions,
1067 lp_cups_options(talloc_tos(), lp_sub, snum), &size)) {
1068 goto out;
1069 }
1070 num_options = 0;
1071 options = NULL;
1072 num_options = cupsParseOptions(cupsoptions, num_options, &options);
1073
1074 if ( num_options )
1075 cupsEncodeOptions(request, num_options, options);
1076
1077 /*
1078 * Do the request and get back a response...
1079 */
1080
1081 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1082 uri,
1083 sizeof(uri),
1084 "ipp",
1085 NULL, /* username */
1086 "localhost",
1087 ippPort(),
1088 "/printers/%s",
1089 printername);
1090 if (ustatus != HTTP_URI_STATUS_OK) {
1091 goto out;
1092 }
1093
1094 if (!push_utf8_talloc(frame, &filename, pjob->filename, &size)) {
1095 goto out;
1096 }
1097 if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) {
1098 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1099 DEBUG(0,("Unable to print file to %s - %s\n",
1100 lp_printername(talloc_tos(), lp_sub, snum),
1101 ippErrorString(cupsLastError())));
1102 } else {
1103 ret = 0;
1104 attr_job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER);
1105 if(attr_job_id) {
1106 pjob->sysjob = ippGetInteger(attr_job_id, 0);
1107 DEBUG(5,("cups_job_submit: job-id %d\n", pjob->sysjob));
1108 } else {
1109 DEBUG(0,("Missing job-id attribute in IPP response"));
1110 }
1111 }
1112 } else {
1113 DEBUG(0,("Unable to print file to `%s' - %s\n",
1114 lp_printername(talloc_tos(), lp_sub, snum),
1115 ippErrorString(cupsLastError())));
1116 }
1117
1118 if ( ret == 0 )
1119 unlink(pjob->filename);
1120 /* else print_job_end will do it for us */
1121
1122 out:
1123 if (response)
1124 ippDelete(response);
1125
1126 if (language)
1127 cupsLangFree(language);
1128
1129 if (http)
1130 httpClose(http);
1131
1132 TALLOC_FREE(frame);
1133
1134 return ret;
1135 }
1136
1137 /*
1138 * 'cups_queue_get()' - Get all the jobs in the print queue.
1139 */
1140
1141 static int cups_queue_get(const char *sharename,
1142 enum printing_types printing_type,
1143 char *lpq_command,
1144 print_queue_struct **q,
1145 print_status_struct *status)
1146 {
1147 TALLOC_CTX *frame = talloc_stackframe();
1148 char *printername = NULL;
1149 http_t *http = NULL; /* HTTP connection to server */
1150 ipp_t *request = NULL, /* IPP Request */
1151 *response = NULL; /* IPP Response */
1152 ipp_attribute_t *attr = NULL; /* Current attribute */
1153 cups_lang_t *language = NULL; /* Default language */
1154 char uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
1155 http_uri_status_t ustatus;
1156 int qcount = 0, /* Number of active queue entries */
1157 qalloc = 0; /* Number of queue entries allocated */
1158 print_queue_struct *queue = NULL, /* Queue entries */
1159 *temp; /* Temporary pointer for queue */
1160 char *user_name = NULL, /* job-originating-user-name attribute */
1161 *job_name = NULL; /* job-name attribute */
1162 int job_id; /* job-id attribute */
1163 int job_k_octets; /* job-k-octets attribute */
1164 time_t job_time; /* time-at-creation attribute */
1165 ipp_jstate_t job_status; /* job-status attribute */
1166 int job_priority; /* job-priority attribute */
1167 size_t size;
1168 static const char *jattrs[] = /* Requested job attributes */
1169 {
1170 "job-id",
1171 "job-k-octets",
1172 "job-name",
1173 "job-originating-user-name",
1174 "job-priority",
1175 "job-state",
1176 "time-at-creation",
1177 };
1178 static const char *pattrs[] = /* Requested printer attributes */
1179 {
1180 "printer-state",
1181 "printer-state-message"
1182 };
1183
1184 *q = NULL;
1185
1186 /* HACK ALERT!!! The problem with support the 'printer name'
1187 option is that we key the tdb off the sharename. So we will
1188 overload the lpq_command string to pass in the printername
1189 (which is basically what we do for non-cups printers ... using
1190 the lpq_command to get the queue listing). */
1191
1192 if (!push_utf8_talloc(frame, &printername, lpq_command, &size)) {
1193 goto out;
1194 }
1195 DEBUG(5,("cups_queue_get(%s, %p, %p)\n", lpq_command, q, status));
1196
1197 /*
1198 * Make sure we don't ask for passwords...
1199 */
1200
1201 cupsSetPasswordCB(cups_passwd_cb);
1202
1203 /*
1204 * Try to connect to the server...
1205 */
1206
1207 if ((http = cups_connect(frame)) == NULL) {
1208 goto out;
1209 }
1210
1211 /*
1212 * Generate the printer URI...
1213 */
1214
1215 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1216 uri,
1217 sizeof(uri),
1218 "ipp",
1219 NULL, /* username */
1220 "localhost",
1221 ippPort(),
1222 "/printers/%s",
1223 printername);
1224 if (ustatus != HTTP_URI_STATUS_OK) {
1225 goto out;
1226 }
1227
1228 /*
1229 * Build an IPP_GET_JOBS request, which requires the following
1230 * attributes:
1231 *
1232 * attributes-charset
1233 * attributes-natural-language
1234 * requested-attributes
1235 * printer-uri
1236 */
1237
1238 request = ippNew();
1239
1240 ippSetOperation(request, IPP_GET_JOBS);
1241 ippSetRequestId(request, 1);
1242
1243 language = cupsLangDefault();
1244
1245 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1246 "attributes-charset", NULL, "utf-8");
1247
1248 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1249 "attributes-natural-language", NULL, language->language);
1250
1251 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1252 "requested-attributes",
1253 (sizeof(jattrs) / sizeof(jattrs[0])),
1254 NULL, jattrs);
1255
1256 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1257 "printer-uri", NULL, uri);
1258
1259 /*
1260 * Do the request and get back a response...
1261 */
1262
1263 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1264 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1265 ippErrorString(cupsLastError())));
1266 goto out;
1267 }
1268
1269 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1270 DEBUG(0,("Unable to get jobs for %s - %s\n", uri,
1271 ippErrorString(ippGetStatusCode(response))));
1272 goto out;
1273 }
1274
1275 /*
1276 * Process the jobs...
1277 */
1278
1279 qcount = 0;
1280 qalloc = 0;
1281 queue = NULL;
1282
1283 for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) {
1284 /*
1285 * Skip leading attributes until we hit a job...
1286 */
1287
1288 while (attr != NULL && ippGetGroupTag(attr) != IPP_TAG_JOB)
1289 attr = ippNextAttribute(response);
1290
1291 if (attr == NULL)
1292 break;
1293
1294 /*
1295 * Allocate memory as needed...
1296 */
1297 if (qcount >= qalloc) {
1298 qalloc += 16;
1299
1300 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc);
1301
1302 if (queue == NULL) {
1303 DEBUG(0,("cups_queue_get: Not enough memory!"));
1304 qcount = 0;
1305 goto out;
1306 }
1307 }
1308
1309 temp = queue + qcount;
1310 memset(temp, 0, sizeof(print_queue_struct));
1311
1312 /*
1313 * Pull the needed attributes from this job...
1314 */
1315
1316 job_id = 0;
1317 job_priority = 50;
1318 job_status = IPP_JOB_PENDING;
1319 job_time = 0;
1320 job_k_octets = 0;
1321 user_name = NULL;
1322 job_name = NULL;
1323
1324 while (attr != NULL && ippGetGroupTag(attr) == IPP_TAG_JOB) {
1325 if (ippGetName(attr) == NULL) {
1326 attr = ippNextAttribute(response);
1327 break;
1328 }
1329
1330 if (strcmp(ippGetName(attr), "job-id") == 0 &&
1331 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1332 job_id = ippGetInteger(attr, 0);
1333
1334 if (strcmp(ippGetName(attr), "job-k-octets") == 0 &&
1335 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1336 job_k_octets = ippGetInteger(attr, 0);
1337
1338 if (strcmp(ippGetName(attr), "job-priority") == 0 &&
1339 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1340 job_priority = ippGetInteger(attr, 0);
1341
1342 if (strcmp(ippGetName(attr), "job-state") == 0 &&
1343 ippGetValueTag(attr) == IPP_TAG_ENUM)
1344 job_status = (ipp_jstate_t)ippGetInteger(attr, 0);
1345
1346 if (strcmp(ippGetName(attr), "time-at-creation") == 0 &&
1347 ippGetValueTag(attr) == IPP_TAG_INTEGER)
1348 job_time = ippGetInteger(attr, 0);
1349
1350 if (strcmp(ippGetName(attr), "job-name") == 0 &&
1351 ippGetValueTag(attr) == IPP_TAG_NAME) {
1352 if (!pull_utf8_talloc(frame,
1353 &job_name,
1354 ippGetString(attr, 0, NULL),
1355 &size)) {
1356 goto out;
1357 }
1358 }
1359
1360 if (strcmp(ippGetName(attr), "job-originating-user-name") == 0 &&
1361 ippGetValueTag(attr) == IPP_TAG_NAME) {
1362 if (!pull_utf8_talloc(frame,
1363 &user_name,
1364 ippGetString(attr, 0, NULL),
1365 &size)) {
1366 goto out;
1367 }
1368 }
1369
1370 attr = ippNextAttribute(response);
1371 }
1372
1373 /*
1374 * See if we have everything needed...
1375 */
1376
1377 if (user_name == NULL || job_name == NULL || job_id == 0) {
1378 if (attr == NULL)
1379 break;
1380 else
1381 continue;
1382 }
1383
1384 temp->sysjob = job_id;
1385 temp->size = job_k_octets * 1024;
1386 temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED :
1387 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED :
1388 job_status == IPP_JOB_HELD ? LPQ_PAUSED :
1389 LPQ_PRINTING;
1390 temp->priority = job_priority;
1391 temp->time = job_time;
1392 strlcpy(temp->fs_user, user_name, sizeof(temp->fs_user));
1393 strlcpy(temp->fs_file, job_name, sizeof(temp->fs_file));
1394
1395 qcount ++;
1396
1397 if (attr == NULL)
1398 break;
1399 }
1400
1401 ippDelete(response);
1402 response = NULL;
1403
1404 /*
1405 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1406 * following attributes:
1407 *
1408 * attributes-charset
1409 * attributes-natural-language
1410 * requested-attributes
1411 * printer-uri
1412 */
1413
1414 request = ippNew();
1415
1416 ippSetOperation(request, IPP_GET_PRINTER_ATTRIBUTES);
1417 ippSetRequestId(request, 1);
1418
1419 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1420 "attributes-charset", NULL, "utf-8");
1421
1422 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1423 "attributes-natural-language", NULL, language->language);
1424
1425 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
1426 "requested-attributes",
1427 (sizeof(pattrs) / sizeof(pattrs[0])),
1428 NULL, pattrs);
1429
1430 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1431 "printer-uri", NULL, uri);
1432
1433 /*
1434 * Do the request and get back a response...
1435 */
1436
1437 if ((response = cupsDoRequest(http, request, "/")) == NULL) {
1438 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1439 ippErrorString(cupsLastError())));
1440 goto out;
1441 }
1442
1443 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1444 DEBUG(0,("Unable to get printer status for %s - %s\n", printername,
1445 ippErrorString(ippGetStatusCode(response))));
1446 goto out;
1447 }
1448
1449 /*
1450 * Get the current printer status and convert it to the SAMBA values.
1451 */
1452
1453 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) {
1454 if (ippGetInteger(attr, 0) == IPP_PRINTER_STOPPED)
1455 status->status = LPSTAT_STOPPED;
1456 else
1457 status->status = LPSTAT_OK;
1458 }
1459
1460 if ((attr = ippFindAttribute(response, "printer-state-message",
1461 IPP_TAG_TEXT)) != NULL) {
1462 char *msg = NULL;
1463 if (!pull_utf8_talloc(frame, &msg,
1464 ippGetString(attr, 0, NULL),
1465 &size)) {
1466 SAFE_FREE(queue);
1467 qcount = 0;
1468 goto out;
1469 }
1470 fstrcpy(status->message, msg);
1471 }
1472
1473 out:
1474
1475 /*
1476 * Return the job queue...
1477 */
1478
1479 *q = queue;
1480
1481 if (response)
1482 ippDelete(response);
1483
1484 if (language)
1485 cupsLangFree(language);
1486
1487 if (http)
1488 httpClose(http);
1489
1490 TALLOC_FREE(frame);
1491 return qcount;
1492 }
1493
1494
1495 /*
1496 * 'cups_queue_pause()' - Pause a print queue.
1497 */
1498
1499 static int cups_queue_pause(int snum)
1500 {
1501 TALLOC_CTX *frame = talloc_stackframe();
1502 const struct loadparm_substitution *lp_sub =
1503 loadparm_s3_global_substitution();
1504 int ret = 1; /* Return value */
1505 http_t *http = NULL; /* HTTP connection to server */
1506 ipp_t *request = NULL, /* IPP Request */
1507 *response = NULL; /* IPP Response */
1508 cups_lang_t *language = NULL; /* Default language */
1509 char *printername = NULL;
1510 char *username = NULL;
1511 char uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
1512 http_uri_status_t ustatus;
1513 size_t size;
1514
1515 DEBUG(5,("cups_queue_pause(%d)\n", snum));
1516
1517 /*
1518 * Make sure we don't ask for passwords...
1519 */
1520
1521 cupsSetPasswordCB(cups_passwd_cb);
1522
1523 /*
1524 * Try to connect to the server...
1525 */
1526
1527 if ((http = cups_connect(frame)) == NULL) {
1528 goto out;
1529 }
1530
1531 /*
1532 * Build an IPP_PAUSE_PRINTER request, which requires the following
1533 * attributes:
1534 *
1535 * attributes-charset
1536 * attributes-natural-language
1537 * printer-uri
1538 * requesting-user-name
1539 */
1540
1541 request = ippNew();
1542
1543 ippSetOperation(request, IPP_PAUSE_PRINTER);
1544 ippSetRequestId(request, 1);
1545
1546 language = cupsLangDefault();
1547
1548 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1549 "attributes-charset", NULL, "utf-8");
1550
1551 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1552 "attributes-natural-language", NULL, language->language);
1553
1554 if (!push_utf8_talloc(frame, &printername,
1555 lp_printername(talloc_tos(), lp_sub, snum), &size)) {
1556 goto out;
1557 }
1558 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1559 uri,
1560 sizeof(uri),
1561 "ipp",
1562 NULL, /* username */
1563 "localhost",
1564 ippPort(),
1565 "/printers/%s",
1566 printername);
1567 if (ustatus != HTTP_URI_STATUS_OK) {
1568 goto out;
1569 }
1570
1571 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1572
1573 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1574 goto out;
1575 }
1576 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1577 NULL, username);
1578
1579 /*
1580 * Do the request and get back a response...
1581 */
1582
1583 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1584 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1585 DEBUG(0,("Unable to pause printer %s - %s\n",
1586 lp_printername(talloc_tos(), lp_sub, snum),
1587 ippErrorString(cupsLastError())));
1588 } else {
1589 ret = 0;
1590 }
1591 } else {
1592 DEBUG(0,("Unable to pause printer %s - %s\n",
1593 lp_printername(talloc_tos(), lp_sub, snum),
1594 ippErrorString(cupsLastError())));
1595 }
1596
1597 out:
1598 if (response)
1599 ippDelete(response);
1600
1601 if (language)
1602 cupsLangFree(language);
1603
1604 if (http)
1605 httpClose(http);
1606
1607 TALLOC_FREE(frame);
1608 return ret;
1609 }
1610
1611
1612 /*
1613 * 'cups_queue_resume()' - Restart a print queue.
1614 */
1615
1616 static int cups_queue_resume(int snum)
1617 {
1618 TALLOC_CTX *frame = talloc_stackframe();
1619 const struct loadparm_substitution *lp_sub =
1620 loadparm_s3_global_substitution();
1621 int ret = 1; /* Return value */
1622 http_t *http = NULL; /* HTTP connection to server */
1623 ipp_t *request = NULL, /* IPP Request */
1624 *response = NULL; /* IPP Response */
1625 cups_lang_t *language = NULL; /* Default language */
1626 char *printername = NULL;
1627 char *username = NULL;
1628 char uri[HTTP_MAX_URI] = {0}; /* printer-uri attribute */
1629 http_uri_status_t ustatus;
1630 size_t size;
1631
1632 DEBUG(5,("cups_queue_resume(%d)\n", snum));
1633
1634 /*
1635 * Make sure we don't ask for passwords...
1636 */
1637
1638 cupsSetPasswordCB(cups_passwd_cb);
1639
1640 /*
1641 * Try to connect to the server...
1642 */
1643
1644 if ((http = cups_connect(frame)) == NULL) {
1645 goto out;
1646 }
1647
1648 /*
1649 * Build an IPP_RESUME_PRINTER request, which requires the following
1650 * attributes:
1651 *
1652 * attributes-charset
1653 * attributes-natural-language
1654 * printer-uri
1655 * requesting-user-name
1656 */
1657
1658 request = ippNew();
1659
1660 ippSetOperation(request, IPP_RESUME_PRINTER);
1661 ippSetRequestId(request, 1);
1662
1663 language = cupsLangDefault();
1664
1665 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
1666 "attributes-charset", NULL, "utf-8");
1667
1668 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1669 "attributes-natural-language", NULL, language->language);
1670
1671 if (!push_utf8_talloc(frame, &printername, lp_printername(talloc_tos(), lp_sub, snum),
1672 &size)) {
1673 goto out;
1674 }
1675 ustatus = httpAssembleURIf(HTTP_URI_CODING_ALL,
1676 uri,
1677 sizeof(uri),
1678 "ipp",
1679 NULL, /* username */
1680 "localhost",
1681 ippPort(),
1682 "/printers/%s",
1683 printername);
1684 if (ustatus != HTTP_URI_STATUS_OK) {
1685 goto out;
1686 }
1687
1688 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
1689
1690 if (!push_utf8_talloc(frame, &username, current_user_info.unix_name, &size)) {
1691 goto out;
1692 }
1693 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1694 NULL, username);
1695
1696 /*
1697 * Do the request and get back a response...
1698 */
1699
1700 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) {
1701 if (ippGetStatusCode(response) >= IPP_OK_CONFLICT) {
1702 DEBUG(0,("Unable to resume printer %s - %s\n",
1703 lp_printername(talloc_tos(), lp_sub, snum),
1704 ippErrorString(cupsLastError())));
1705 } else {
1706 ret = 0;
1707 }
1708 } else {
1709 DEBUG(0,("Unable to resume printer %s - %s\n",
1710 lp_printername(talloc_tos(), lp_sub, snum),
1711 ippErrorString(cupsLastError())));
1712 }
1713
1714 out:
1715 if (response)
1716 ippDelete(response);
1717
1718 if (language)
1719 cupsLangFree(language);
1720
1721 if (http)
1722 httpClose(http);
1723
1724 TALLOC_FREE(frame);
1725 return ret;
1726 }
1727
1728 /*******************************************************************
1729 * CUPS printing interface definitions...
1730 ******************************************************************/
1731
1732 struct printif cups_printif =
1733 {
1734 PRINT_CUPS,
1735 cups_queue_get,
1736 cups_queue_pause,
1737 cups_queue_resume,
1738 cups_job_delete,
1739 cups_job_pause,
1740 cups_job_resume,
1741 cups_job_submit,
1742 };
1743
1744 #else
1745 /* this keeps fussy compilers happy */
1746 void print_cups_dummy(void);
1747 void print_cups_dummy(void) {}
1748 #endif /* HAVE_CUPS */
1749