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