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