1/* 2 * Support code for Novell iPrint using the Common UNIX Printing 3 * System ("CUPS") libraries 4 * 5 * Copyright 1999-2003 by Michael R Sweet. 6 * Portions Copyright 2005 by Joel J. Smith. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, see <http://www.gnu.org/licenses/>. 20 */ 21 22#include "includes.h" 23#include "printing.h" 24 25#ifdef HAVE_IPRINT 26#include <cups/cups.h> 27#include <cups/language.h> 28 29#define OPERATION_NOVELL_LIST_PRINTERS 0x401A 30#define OPERATION_NOVELL_MGMT 0x401C 31#define NOVELL_SERVER_SYSNAME "sysname=" 32#define NOVELL_SERVER_SYSNAME_NETWARE "NetWare IA32" 33#define NOVELL_SERVER_VERSION_STRING "iprintserverversion=" 34#define NOVELL_SERVER_VERSION_OES_SP1 33554432 35 36/* 37 * 'iprint_passwd_cb()' - The iPrint password callback... 38 */ 39 40static const char * /* O - Password or NULL */ 41iprint_passwd_cb(const char *prompt) /* I - Prompt */ 42{ 43 /* 44 * Always return NULL to indicate that no password is available... 45 */ 46 47 return (NULL); 48} 49 50static const char *iprint_server(void) 51{ 52 if ((lp_iprint_server() != NULL) && (strlen(lp_iprint_server()) > 0)) { 53 DEBUG(10, ("iprint server explicitly set to %s\n", 54 lp_iprint_server())); 55 return lp_iprint_server(); 56 } 57 58 DEBUG(10, ("iprint server left to default %s\n", cupsServer())); 59 return cupsServer(); 60} 61 62/* 63 * Pass in an already connected http_t* 64 * Returns the server version if one can be found, multiplied by 65 * -1 for all NetWare versions. Returns 0 if a server version 66 * cannot be determined 67 */ 68 69static int iprint_get_server_version(http_t *http, char* serviceUri) 70{ 71 ipp_t *request = NULL, /* IPP Request */ 72 *response = NULL; /* IPP Response */ 73 ipp_attribute_t *attr; /* Current attribute */ 74 cups_lang_t *language = NULL; /* Default language */ 75 char *ver; /* server version pointer */ 76 char *vertmp; /* server version tmp pointer */ 77 int serverVersion = 0; /* server version */ 78 char *os; /* server os */ 79 int osFlag = 0; /* 0 for NetWare, 1 for anything else */ 80 char *temp; /* pointer for string manipulation */ 81 82 /* 83 * Build an OPERATION_NOVELL_MGMT("get-server-version") request, 84 * which requires the following attributes: 85 * 86 * attributes-charset 87 * attributes-natural-language 88 * operation-name 89 * service-uri 90 */ 91 92 request = ippNew(); 93 94 request->request.op.operation_id = (ipp_op_t)OPERATION_NOVELL_MGMT; 95 request->request.op.request_id = 1; 96 97 language = cupsLangDefault(); 98 99 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 100 "attributes-charset", NULL, "utf-8"); 101 102 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 103 "attributes-natural-language", NULL, language->language); 104 105 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 106 "service-uri", NULL, serviceUri); 107 108 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 109 "operation-name", NULL, "get-server-version"); 110 111 /* 112 * Do the request and get back a response... 113 */ 114 115 if (((response = cupsDoRequest(http, request, "/ipp/")) == NULL) || 116 (response->request.status.status_code >= IPP_OK_CONFLICT)) 117 goto out; 118 119 if (((attr = ippFindAttribute(response, "server-version", 120 IPP_TAG_STRING)) != NULL)) { 121 if ((ver = strstr(attr->values[0].string.text, 122 NOVELL_SERVER_VERSION_STRING)) != NULL) { 123 ver += strlen(NOVELL_SERVER_VERSION_STRING); 124 /* 125 * Strangely, libcups stores a IPP_TAG_STRING (octet 126 * string) as a null-terminated string with no length 127 * even though it could be binary data with nulls in 128 * it. Luckily, in this case the value is not binary. 129 */ 130 serverVersion = strtol(ver, &vertmp, 10); 131 132 /* Check for not found, overflow or negative version */ 133 if ((ver == vertmp) || (serverVersion < 0)) 134 serverVersion = 0; 135 } 136 137 if ((os = strstr(attr->values[0].string.text, 138 NOVELL_SERVER_SYSNAME)) != NULL) { 139 os += strlen(NOVELL_SERVER_SYSNAME); 140 if ((temp = strchr(os,'<')) != NULL) 141 *temp = '\0'; 142 if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE)) 143 osFlag = 1; /* 1 for non-NetWare systems */ 144 } 145 } 146 147 out: 148 if (response) 149 ippDelete(response); 150 151 if (language) 152 cupsLangFree(language); 153 154 if (osFlag == 0) 155 serverVersion *= -1; 156 157 return serverVersion; 158} 159 160 161static int iprint_cache_add_printer(http_t *http, 162 int reqId, 163 char* url) 164{ 165 ipp_t *request = NULL, /* IPP Request */ 166 *response = NULL; /* IPP Response */ 167 ipp_attribute_t *attr; /* Current attribute */ 168 cups_lang_t *language = NULL; /* Default language */ 169 char *name, /* printer-name attribute */ 170 *info, /* printer-info attribute */ 171 smb_enabled, /* smb-enabled attribute */ 172 secure; /* security-enabled attrib. */ 173 174 char *httpPath; /* path portion of the printer-uri */ 175 176 static const char *pattrs[] = /* Requested printer attributes */ 177 { 178 "printer-name", 179 "security-enabled", 180 "printer-info", 181 "smb-enabled" 182 }; 183 184 request = ippNew(); 185 186 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; 187 request->request.op.request_id = reqId; 188 189 language = cupsLangDefault(); 190 191 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 192 "attributes-charset", NULL, "utf-8"); 193 194 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 195 "attributes-natural-language", NULL, language->language); 196 197 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, url); 198 199 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 200 "requested-attributes", 201 (sizeof(pattrs) / sizeof(pattrs[0])), 202 NULL, pattrs); 203 204 /* 205 * Do the request and get back a response... 206 */ 207 208 if ((httpPath = strstr(url,"://")) == NULL || 209 (httpPath = strchr(httpPath+3,'/')) == NULL) 210 { 211 ippDelete(request); 212 request = NULL; 213 goto out; 214 } 215 216 if ((response = cupsDoRequest(http, request, httpPath)) == NULL) { 217 ipp_status_t lastErr = cupsLastError(); 218 219 /* 220 * Ignore printers that cannot be queried without credentials 221 */ 222 if (lastErr == IPP_FORBIDDEN || 223 lastErr == IPP_NOT_AUTHENTICATED || 224 lastErr == IPP_NOT_AUTHORIZED) 225 goto out; 226 227 DEBUG(0,("Unable to get printer list - %s\n", 228 ippErrorString(lastErr))); 229 goto out; 230 } 231 232 for (attr = response->attrs; attr != NULL;) { 233 /* 234 * Skip leading attributes until we hit a printer... 235 */ 236 237 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 238 attr = attr->next; 239 240 if (attr == NULL) 241 break; 242 243 /* 244 * Pull the needed attributes from this printer... 245 */ 246 247 name = NULL; 248 info = NULL; 249 smb_enabled= 1; 250 secure = 0; 251 252 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) { 253 if (strcmp(attr->name, "printer-name") == 0 && 254 attr->value_tag == IPP_TAG_NAME) 255 name = attr->values[0].string.text; 256 257 if (strcmp(attr->name, "printer-info") == 0 && 258 (attr->value_tag == IPP_TAG_TEXT || 259 attr->value_tag == IPP_TAG_TEXTLANG)) 260 info = attr->values[0].string.text; 261 262 /* 263 * If the smb-enabled attribute is present and the 264 * value is set to 0, don't show the printer. 265 * If the attribute is not present, assume that the 266 * printer should show up 267 */ 268 if (!strcmp(attr->name, "smb-enabled") && 269 ((attr->value_tag == IPP_TAG_INTEGER && 270 !attr->values[0].integer) || 271 (attr->value_tag == IPP_TAG_BOOLEAN && 272 !attr->values[0].boolean))) 273 smb_enabled = 0; 274 275 /* 276 * If the security-enabled attribute is present and the 277 * value is set to 1, don't show the printer. 278 * If the attribute is not present, assume that the 279 * printer should show up 280 */ 281 if (!strcmp(attr->name, "security-enabled") && 282 ((attr->value_tag == IPP_TAG_INTEGER && 283 attr->values[0].integer) || 284 (attr->value_tag == IPP_TAG_BOOLEAN && 285 attr->values[0].boolean))) 286 secure = 1; 287 288 attr = attr->next; 289 } 290 291 /* 292 * See if we have everything needed... 293 * Make sure the printer is not a secure printer 294 * and make sure smb printing hasn't been explicitly 295 * disabled for the printer 296 */ 297 298 if (name != NULL && !secure && smb_enabled) 299 pcap_cache_add(name, info); 300 } 301 302 out: 303 if (response) 304 ippDelete(response); 305 return(0); 306} 307 308bool iprint_cache_reload(void) 309{ 310 http_t *http = NULL; /* HTTP connection to server */ 311 ipp_t *request = NULL, /* IPP Request */ 312 *response = NULL; /* IPP Response */ 313 ipp_attribute_t *attr; /* Current attribute */ 314 cups_lang_t *language = NULL; /* Default language */ 315 int i; 316 bool ret = False; 317 318 DEBUG(5, ("reloading iprint printcap cache\n")); 319 320 /* 321 * Make sure we don't ask for passwords... 322 */ 323 324 cupsSetPasswordCB(iprint_passwd_cb); 325 326 /* 327 * Try to connect to the server... 328 */ 329 330 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 331 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 332 iprint_server(), strerror(errno))); 333 goto out; 334 } 335 336 /* 337 * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes: 338 * 339 * attributes-charset 340 * attributes-natural-language 341 */ 342 343 request = ippNew(); 344 345 request->request.op.operation_id = 346 (ipp_op_t)OPERATION_NOVELL_LIST_PRINTERS; 347 request->request.op.request_id = 1; 348 349 language = cupsLangDefault(); 350 351 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 352 "attributes-charset", NULL, "utf-8"); 353 354 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 355 "attributes-natural-language", NULL, language->language); 356 357 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 358 "ipp-server", NULL, "ippSrvr"); 359 360 /* 361 * Do the request and get back a response... 362 */ 363 364 if ((response = cupsDoRequest(http, request, "/ipp")) == NULL) { 365 DEBUG(0,("Unable to get printer list - %s\n", 366 ippErrorString(cupsLastError()))); 367 goto out; 368 } 369 370 for (attr = response->attrs; attr != NULL;) { 371 /* 372 * Skip leading attributes until we hit a printer... 373 */ 374 375 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 376 attr = attr->next; 377 378 if (attr == NULL) 379 break; 380 381 /* 382 * Pull the needed attributes from this printer... 383 */ 384 385 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) 386 { 387 if (strcmp(attr->name, "printer-name") == 0 && 388 (attr->value_tag == IPP_TAG_URI || 389 attr->value_tag == IPP_TAG_NAME || 390 attr->value_tag == IPP_TAG_TEXT || 391 attr->value_tag == IPP_TAG_NAMELANG || 392 attr->value_tag == IPP_TAG_TEXTLANG)) 393 { 394 for (i = 0; i<attr->num_values; i++) 395 { 396 char *url = attr->values[i].string.text; 397 if (!url || !strlen(url)) 398 continue; 399 iprint_cache_add_printer(http, i+2, url); 400 } 401 } 402 attr = attr->next; 403 } 404 } 405 406 ret = True; 407 408 out: 409 if (response) 410 ippDelete(response); 411 412 if (language) 413 cupsLangFree(language); 414 415 if (http) 416 httpClose(http); 417 418 return ret; 419} 420 421 422/* 423 * 'iprint_job_delete()' - Delete a job. 424 */ 425 426static int iprint_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob) 427{ 428 int ret = 1; /* Return value */ 429 http_t *http = NULL; /* HTTP connection to server */ 430 ipp_t *request = NULL, /* IPP Request */ 431 *response = NULL; /* IPP Response */ 432 cups_lang_t *language = NULL; /* Default language */ 433 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 434 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */ 435 436 437 DEBUG(5,("iprint_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob)); 438 439 /* 440 * Make sure we don't ask for passwords... 441 */ 442 443 cupsSetPasswordCB(iprint_passwd_cb); 444 445 /* 446 * Try to connect to the server... 447 */ 448 449 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 450 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 451 iprint_server(), strerror(errno))); 452 goto out; 453 } 454 455 /* 456 * Build an IPP_CANCEL_JOB request, which uses the following 457 * attributes: 458 * 459 * attributes-charset 460 * attributes-natural-language 461 * printer-uri 462 * job-id 463 * requesting-user-name 464 */ 465 466 request = ippNew(); 467 468 request->request.op.operation_id = IPP_CANCEL_JOB; 469 request->request.op.request_id = 1; 470 471 language = cupsLangDefault(); 472 473 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 474 "attributes-charset", NULL, "utf-8"); 475 476 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 477 "attributes-natural-language", NULL, language->language); 478 479 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), sharename); 480 481 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); 482 483 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob); 484 485 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 486 NULL, pjob->user); 487 488 /* 489 * Do the request and get back a response... 490 */ 491 492 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", sharename); 493 494 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) { 495 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 496 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob, 497 ippErrorString(cupsLastError()))); 498 } else { 499 ret = 0; 500 } 501 } else { 502 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob, 503 ippErrorString(cupsLastError()))); 504 } 505 506 out: 507 if (response) 508 ippDelete(response); 509 510 if (language) 511 cupsLangFree(language); 512 513 if (http) 514 httpClose(http); 515 516 return ret; 517} 518 519 520/* 521 * 'iprint_job_pause()' - Pause a job. 522 */ 523 524static int iprint_job_pause(int snum, struct printjob *pjob) 525{ 526 int ret = 1; /* Return value */ 527 http_t *http = NULL; /* HTTP connection to server */ 528 ipp_t *request = NULL, /* IPP Request */ 529 *response = NULL; /* IPP Response */ 530 cups_lang_t *language = NULL; /* Default language */ 531 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 532 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */ 533 534 535 DEBUG(5,("iprint_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); 536 537 /* 538 * Make sure we don't ask for passwords... 539 */ 540 541 cupsSetPasswordCB(iprint_passwd_cb); 542 543 /* 544 * Try to connect to the server... 545 */ 546 547 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 548 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 549 iprint_server(), strerror(errno))); 550 goto out; 551 } 552 553 /* 554 * Build an IPP_HOLD_JOB request, which requires the following 555 * attributes: 556 * 557 * attributes-charset 558 * attributes-natural-language 559 * printer-uri 560 * job-id 561 * requesting-user-name 562 */ 563 564 request = ippNew(); 565 566 request->request.op.operation_id = IPP_HOLD_JOB; 567 request->request.op.request_id = 1; 568 569 language = cupsLangDefault(); 570 571 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 572 "attributes-charset", NULL, "utf-8"); 573 574 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 575 "attributes-natural-language", NULL, language->language); 576 577 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum)); 578 579 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); 580 581 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob); 582 583 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 584 NULL, pjob->user); 585 586 /* 587 * Do the request and get back a response... 588 */ 589 590 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum)); 591 592 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) { 593 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 594 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob, 595 ippErrorString(cupsLastError()))); 596 } else { 597 ret = 0; 598 } 599 } else { 600 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob, 601 ippErrorString(cupsLastError()))); 602 } 603 604 out: 605 if (response) 606 ippDelete(response); 607 608 if (language) 609 cupsLangFree(language); 610 611 if (http) 612 httpClose(http); 613 614 return ret; 615} 616 617 618/* 619 * 'iprint_job_resume()' - Resume a paused job. 620 */ 621 622static int iprint_job_resume(int snum, struct printjob *pjob) 623{ 624 int ret = 1; /* Return value */ 625 http_t *http = NULL; /* HTTP connection to server */ 626 ipp_t *request = NULL, /* IPP Request */ 627 *response = NULL; /* IPP Response */ 628 cups_lang_t *language = NULL; /* Default language */ 629 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 630 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */ 631 632 633 DEBUG(5,("iprint_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); 634 635 /* 636 * Make sure we don't ask for passwords... 637 */ 638 639 cupsSetPasswordCB(iprint_passwd_cb); 640 641 /* 642 * Try to connect to the server... 643 */ 644 645 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 646 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 647 iprint_server(), strerror(errno))); 648 goto out; 649 } 650 651 /* 652 * Build an IPP_RELEASE_JOB request, which requires the following 653 * attributes: 654 * 655 * attributes-charset 656 * attributes-natural-language 657 * printer-uri 658 * job-id 659 * requesting-user-name 660 */ 661 662 request = ippNew(); 663 664 request->request.op.operation_id = IPP_RELEASE_JOB; 665 request->request.op.request_id = 1; 666 667 language = cupsLangDefault(); 668 669 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 670 "attributes-charset", NULL, "utf-8"); 671 672 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 673 "attributes-natural-language", NULL, language->language); 674 675 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum)); 676 677 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); 678 679 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob); 680 681 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 682 NULL, pjob->user); 683 684 /* 685 * Do the request and get back a response... 686 */ 687 688 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum)); 689 690 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) { 691 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 692 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob, 693 ippErrorString(cupsLastError()))); 694 } else { 695 ret = 0; 696 } 697 } else { 698 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob, 699 ippErrorString(cupsLastError()))); 700 } 701 702 out: 703 if (response) 704 ippDelete(response); 705 706 if (language) 707 cupsLangFree(language); 708 709 if (http) 710 httpClose(http); 711 712 return ret; 713} 714 715 716/* 717 * 'iprint_job_submit()' - Submit a job for printing. 718 */ 719 720static int iprint_job_submit(int snum, struct printjob *pjob) 721{ 722 int ret = 1; /* Return value */ 723 http_t *http = NULL; /* HTTP connection to server */ 724 ipp_t *request = NULL, /* IPP Request */ 725 *response = NULL; /* IPP Response */ 726 ipp_attribute_t *attr; /* Current attribute */ 727 cups_lang_t *language = NULL; /* Default language */ 728 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 729 const char *clientname = NULL; /* hostname of client for job-originating-host attribute */ 730 char addr[INET6_ADDRSTRLEN]; 731 732 DEBUG(5,("iprint_job_submit(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); 733 734 /* 735 * Make sure we don't ask for passwords... 736 */ 737 738 cupsSetPasswordCB(iprint_passwd_cb); 739 740 /* 741 * Try to connect to the server... 742 */ 743 744 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 745 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 746 iprint_server(), strerror(errno))); 747 goto out; 748 } 749 750 /* 751 * Build an IPP_PRINT_JOB request, which requires the following 752 * attributes: 753 * 754 * attributes-charset 755 * attributes-natural-language 756 * printer-uri 757 * requesting-user-name 758 * [document-data] 759 */ 760 761 request = ippNew(); 762 763 request->request.op.operation_id = IPP_PRINT_JOB; 764 request->request.op.request_id = 1; 765 766 language = cupsLangDefault(); 767 768 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 769 "attributes-charset", NULL, "utf-8"); 770 771 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 772 "attributes-natural-language", NULL, language->language); 773 774 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum)); 775 776 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 777 "printer-uri", NULL, uri); 778 779 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 780 NULL, pjob->user); 781 782 clientname = client_name(get_client_fd()); 783 if (strcmp(clientname, "UNKNOWN") == 0) { 784 clientname = client_addr(get_client_fd(),addr,sizeof(addr)); 785 } 786 787 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 788 "job-originating-host-name", NULL, 789 clientname); 790 791 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, 792 pjob->jobname); 793 794 /* 795 * Do the request and get back a response... 796 */ 797 798 slprintf(uri, sizeof(uri) - 1, "/ipp/%s", PRINTERNAME(snum)); 799 800 if ((response = cupsDoFileRequest(http, request, uri, pjob->filename)) != NULL) { 801 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 802 DEBUG(0,("Unable to print file to %s - %s\n", PRINTERNAME(snum), 803 ippErrorString(cupsLastError()))); 804 } else { 805 ret = 0; 806 } 807 } else { 808 DEBUG(0,("Unable to print file to `%s' - %s\n", PRINTERNAME(snum), 809 ippErrorString(cupsLastError()))); 810 } 811 812 if ( ret == 0 ) 813 unlink(pjob->filename); 814 /* else print_job_end will do it for us */ 815 816 if ( ret == 0 ) { 817 818 attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER); 819 if (attr != NULL && attr->group_tag == IPP_TAG_JOB) 820 { 821 pjob->sysjob = attr->values[0].integer; 822 } 823 } 824 825 out: 826 if (response) 827 ippDelete(response); 828 829 if (language) 830 cupsLangFree(language); 831 832 if (http) 833 httpClose(http); 834 835 return ret; 836} 837 838/* 839 * 'iprint_queue_get()' - Get all the jobs in the print queue. 840 */ 841 842static int iprint_queue_get(const char *sharename, 843 enum printing_types printing_type, 844 char *lpq_command, 845 print_queue_struct **q, 846 print_status_struct *status) 847{ 848 fstring printername; 849 http_t *http = NULL; /* HTTP connection to server */ 850 ipp_t *request = NULL, /* IPP Request */ 851 *response = NULL; /* IPP Response */ 852 ipp_attribute_t *attr = NULL; /* Current attribute */ 853 cups_lang_t *language = NULL; /* Default language */ 854 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 855 char serviceUri[HTTP_MAX_URI]; /* service-uri attribute */ 856 char httpPath[HTTP_MAX_URI]; /* path portion of the uri */ 857 int jobUseUnixTime = 0; /* Whether job times should 858 * be assumed to be Unix time */ 859 int qcount = 0, /* Number of active queue entries */ 860 qalloc = 0; /* Number of queue entries allocated */ 861 print_queue_struct *queue = NULL, /* Queue entries */ 862 *temp; /* Temporary pointer for queue */ 863 const char *user_name, /* job-originating-user-name attribute */ 864 *job_name; /* job-name attribute */ 865 int job_id; /* job-id attribute */ 866 int job_k_octets; /* job-k-octets attribute */ 867 time_t job_time; /* time-at-creation attribute */ 868 time_t printer_current_time = 0; /* printer's current time */ 869 time_t printer_up_time = 0; /* printer's uptime */ 870 ipp_jstate_t job_status; /* job-status attribute */ 871 int job_priority; /* job-priority attribute */ 872 static const char *jattrs[] = /* Requested job attributes */ 873 { 874 "job-id", 875 "job-k-octets", 876 "job-name", 877 "job-originating-user-name", 878 "job-priority", 879 "job-state", 880 "time-at-creation", 881 }; 882 static const char *pattrs[] = /* Requested printer attributes */ 883 { 884 "printer-state", 885 "printer-state-message", 886 "printer-current-time", 887 "printer-up-time" 888 }; 889 890 *q = NULL; 891 892 /* HACK ALERT!!! The porblem with support the 'printer name' 893 option is that we key the tdb off the sharename. So we will 894 overload the lpq_command string to pass in the printername 895 (which is basically what we do for non-cups printers ... using 896 the lpq_command to get the queue listing). */ 897 898 fstrcpy( printername, lpq_command ); 899 900 DEBUG(5,("iprint_queue_get(%s, %p, %p)\n", printername, q, status)); 901 902 /* 903 * Make sure we don't ask for passwords... 904 */ 905 906 cupsSetPasswordCB(iprint_passwd_cb); 907 908 /* 909 * Try to connect to the server... 910 */ 911 912 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 913 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 914 iprint_server(), strerror(errno))); 915 goto out; 916 } 917 918 /* 919 * Generate the printer URI and the service URI that goes with it... 920 */ 921 922 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), printername); 923 slprintf(serviceUri, sizeof(serviceUri) - 1, "ipp://%s/ipp/", iprint_server()); 924 925 /* 926 * For Linux iPrint servers from OES SP1 on, the iPrint server 927 * uses Unix time for job start times unless it detects the iPrint 928 * client in an http User-Agent header. (This was done to accomodate 929 * CUPS broken behavior. According to RFC 2911, section 4.3.14, job 930 * start times are supposed to be relative to how long the printer has 931 * been up.) Since libcups doesn't allow us to set that header before 932 * the request is sent, this ugly hack allows us to detect the server 933 * version and decide how to interpret the job time. 934 */ 935 if (iprint_get_server_version(http, serviceUri) >= 936 NOVELL_SERVER_VERSION_OES_SP1) 937 jobUseUnixTime = 1; 938 939 request = ippNew(); 940 941 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; 942 request->request.op.request_id = 2; 943 944 language = cupsLangDefault(); 945 946 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 947 "attributes-charset", NULL, "utf-8"); 948 949 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 950 "attributes-natural-language", NULL, language->language); 951 952 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 953 "printer-uri", NULL, uri); 954 955 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 956 "requested-attributes", 957 (sizeof(pattrs) / sizeof(pattrs[0])), 958 NULL, pattrs); 959 960 /* 961 * Do the request and get back a response... 962 */ 963 964 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername); 965 966 if ((response = cupsDoRequest(http, request, httpPath)) == NULL) { 967 DEBUG(0,("Unable to get printer status for %s - %s\n", printername, 968 ippErrorString(cupsLastError()))); 969 *q = queue; 970 goto out; 971 } 972 973 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 974 DEBUG(0,("Unable to get printer status for %s - %s\n", printername, 975 ippErrorString(response->request.status.status_code))); 976 *q = queue; 977 goto out; 978 } 979 980 /* 981 * Get the current printer status and convert it to the SAMBA values. 982 */ 983 984 if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) { 985 if (attr->values[0].integer == IPP_PRINTER_STOPPED) 986 status->status = LPSTAT_STOPPED; 987 else 988 status->status = LPSTAT_OK; 989 } 990 991 if ((attr = ippFindAttribute(response, "printer-state-message", 992 IPP_TAG_TEXT)) != NULL) 993 fstrcpy(status->message, attr->values[0].string.text); 994 995 if ((attr = ippFindAttribute(response, "printer-current-time", 996 IPP_TAG_DATE)) != NULL) 997 printer_current_time = ippDateToTime(attr->values[0].date); 998 999 if ((attr = ippFindAttribute(response, "printer-up-time", 1000 IPP_TAG_INTEGER)) != NULL) 1001 printer_up_time = attr->values[0].integer; 1002 1003 ippDelete(response); 1004 response = NULL; 1005 1006 /* 1007 * Build an IPP_GET_JOBS request, which requires the following 1008 * attributes: 1009 * 1010 * attributes-charset 1011 * attributes-natural-language 1012 * requested-attributes 1013 * printer-uri 1014 */ 1015 1016 request = ippNew(); 1017 1018 request->request.op.operation_id = IPP_GET_JOBS; 1019 request->request.op.request_id = 3; 1020 1021 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 1022 "attributes-charset", NULL, "utf-8"); 1023 1024 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 1025 "attributes-natural-language", NULL, language->language); 1026 1027 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 1028 "printer-uri", NULL, uri); 1029 1030 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1031 "requested-attributes", 1032 (sizeof(jattrs) / sizeof(jattrs[0])), 1033 NULL, jattrs); 1034 1035 /* 1036 * Do the request and get back a response... 1037 */ 1038 1039 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", printername); 1040 1041 if ((response = cupsDoRequest(http, request, httpPath)) == NULL) { 1042 DEBUG(0,("Unable to get jobs for %s - %s\n", uri, 1043 ippErrorString(cupsLastError()))); 1044 goto out; 1045 } 1046 1047 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 1048 DEBUG(0,("Unable to get jobs for %s - %s\n", uri, 1049 ippErrorString(response->request.status.status_code))); 1050 goto out; 1051 } 1052 1053 /* 1054 * Process the jobs... 1055 */ 1056 1057 qcount = 0; 1058 qalloc = 0; 1059 queue = NULL; 1060 1061 for (attr = response->attrs; attr != NULL; attr = attr->next) { 1062 /* 1063 * Skip leading attributes until we hit a job... 1064 */ 1065 1066 while (attr != NULL && attr->group_tag != IPP_TAG_JOB) 1067 attr = attr->next; 1068 1069 if (attr == NULL) 1070 break; 1071 1072 /* 1073 * Allocate memory as needed... 1074 */ 1075 if (qcount >= qalloc) { 1076 qalloc += 16; 1077 1078 queue = SMB_REALLOC_ARRAY(queue, print_queue_struct, qalloc); 1079 1080 if (queue == NULL) { 1081 DEBUG(0,("iprint_queue_get: Not enough memory!")); 1082 qcount = 0; 1083 goto out; 1084 } 1085 } 1086 1087 temp = queue + qcount; 1088 memset(temp, 0, sizeof(print_queue_struct)); 1089 1090 /* 1091 * Pull the needed attributes from this job... 1092 */ 1093 1094 job_id = 0; 1095 job_priority = 50; 1096 job_status = IPP_JOB_PENDING; 1097 job_time = 0; 1098 job_k_octets = 0; 1099 user_name = NULL; 1100 job_name = NULL; 1101 1102 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) { 1103 if (attr->name == NULL) { 1104 attr = attr->next; 1105 break; 1106 } 1107 1108 if (strcmp(attr->name, "job-id") == 0 && 1109 attr->value_tag == IPP_TAG_INTEGER) 1110 job_id = attr->values[0].integer; 1111 1112 if (strcmp(attr->name, "job-k-octets") == 0 && 1113 attr->value_tag == IPP_TAG_INTEGER) 1114 job_k_octets = attr->values[0].integer; 1115 1116 if (strcmp(attr->name, "job-priority") == 0 && 1117 attr->value_tag == IPP_TAG_INTEGER) 1118 job_priority = attr->values[0].integer; 1119 1120 if (strcmp(attr->name, "job-state") == 0 && 1121 attr->value_tag == IPP_TAG_ENUM) 1122 job_status = (ipp_jstate_t)(attr->values[0].integer); 1123 1124 if (strcmp(attr->name, "time-at-creation") == 0 && 1125 attr->value_tag == IPP_TAG_INTEGER) 1126 { 1127 /* 1128 * If jobs times are in Unix time, the accuracy of the job 1129 * start time depends upon the iPrint server's time being 1130 * set correctly. Otherwise, the accuracy depends upon 1131 * the Samba server's time being set correctly 1132 */ 1133 1134 if (jobUseUnixTime) 1135 job_time = attr->values[0].integer; 1136 else 1137 job_time = time(NULL) - printer_up_time + attr->values[0].integer; 1138 } 1139 1140 if (strcmp(attr->name, "job-name") == 0 && 1141 (attr->value_tag == IPP_TAG_NAMELANG || 1142 attr->value_tag == IPP_TAG_NAME)) 1143 job_name = attr->values[0].string.text; 1144 1145 if (strcmp(attr->name, "job-originating-user-name") == 0 && 1146 (attr->value_tag == IPP_TAG_NAMELANG || 1147 attr->value_tag == IPP_TAG_NAME)) 1148 user_name = attr->values[0].string.text; 1149 1150 attr = attr->next; 1151 } 1152 1153 /* 1154 * See if we have everything needed... 1155 */ 1156 1157 if (user_name == NULL || job_name == NULL || job_id == 0) { 1158 if (attr == NULL) 1159 break; 1160 else 1161 continue; 1162 } 1163 1164 temp->job = job_id; 1165 temp->size = job_k_octets * 1024; 1166 temp->status = job_status == IPP_JOB_PENDING ? LPQ_QUEUED : 1167 job_status == IPP_JOB_STOPPED ? LPQ_PAUSED : 1168 job_status == IPP_JOB_HELD ? LPQ_PAUSED : 1169 LPQ_PRINTING; 1170 temp->priority = job_priority; 1171 temp->time = job_time; 1172 strncpy(temp->fs_user, user_name, sizeof(temp->fs_user) - 1); 1173 strncpy(temp->fs_file, job_name, sizeof(temp->fs_file) - 1); 1174 1175 qcount ++; 1176 1177 if (attr == NULL) 1178 break; 1179 } 1180 1181 /* 1182 * Return the job queue... 1183 */ 1184 1185 *q = queue; 1186 1187 out: 1188 if (response) 1189 ippDelete(response); 1190 1191 if (language) 1192 cupsLangFree(language); 1193 1194 if (http) 1195 httpClose(http); 1196 1197 return qcount; 1198} 1199 1200 1201/* 1202 * 'iprint_queue_pause()' - Pause a print queue. 1203 */ 1204 1205static int iprint_queue_pause(int snum) 1206{ 1207 return(-1); /* Not supported without credentials */ 1208} 1209 1210 1211/* 1212 * 'iprint_queue_resume()' - Restart a print queue. 1213 */ 1214 1215static int iprint_queue_resume(int snum) 1216{ 1217 return(-1); /* Not supported without credentials */ 1218} 1219 1220/******************************************************************* 1221 * iPrint printing interface definitions... 1222 ******************************************************************/ 1223 1224struct printif iprint_printif = 1225{ 1226 PRINT_IPRINT, 1227 iprint_queue_get, 1228 iprint_queue_pause, 1229 iprint_queue_resume, 1230 iprint_job_delete, 1231 iprint_job_pause, 1232 iprint_job_resume, 1233 iprint_job_submit, 1234}; 1235 1236#else 1237 /* this keeps fussy compilers happy */ 1238 void print_iprint_dummy(void); 1239 void print_iprint_dummy(void) {} 1240#endif /* HAVE_IPRINT */ 1241