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 2 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, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23#include "includes.h" 24#include "printing.h" 25 26#ifdef HAVE_IPRINT 27#include <cups/cups.h> 28#include <cups/language.h> 29 30#define OPERATION_NOVELL_LIST_PRINTERS 0x401A 31#define OPERATION_NOVELL_MGMT 0x401C 32#define NOVELL_SERVER_SYSNAME "sysname=" 33#define NOVELL_SERVER_SYSNAME_NETWARE "NetWare IA32" 34#define NOVELL_SERVER_VERSION_STRING "iprintserverversion=" 35#define NOVELL_SERVER_VERSION_OES_SP1 33554432 36 37/* 38 * 'iprint_passwd_cb()' - The iPrint password callback... 39 */ 40 41static const char * /* O - Password or NULL */ 42iprint_passwd_cb(const char *prompt) /* I - Prompt */ 43{ 44 /* 45 * Always return NULL to indicate that no password is available... 46 */ 47 48 return (NULL); 49} 50 51static const char *iprint_server(void) 52{ 53 if ((lp_iprint_server() != NULL) && (strlen(lp_iprint_server()) > 0)) { 54 DEBUG(10, ("iprint server explicitly set to %s\n", 55 lp_iprint_server())); 56 return lp_iprint_server(); 57 } 58 59 DEBUG(10, ("iprint server left to default %s\n", cupsServer())); 60 return cupsServer(); 61} 62 63/* 64 * Pass in an already connected http_t* 65 * Returns the server version if one can be found, multiplied by 66 * -1 for all NetWare versions. Returns 0 if a server version 67 * cannot be determined 68 */ 69 70static int iprint_get_server_version(http_t *http, char* serviceUri) 71{ 72 ipp_t *request = NULL, /* IPP Request */ 73 *response = NULL; /* IPP Response */ 74 ipp_attribute_t *attr; /* Current attribute */ 75 cups_lang_t *language = NULL; /* Default language */ 76 char *ver; /* server version pointer */ 77 char *vertmp; /* server version tmp pointer */ 78 int serverVersion = 0; /* server version */ 79 char *os; /* server os */ 80 int osFlag = 0; /* 0 for NetWare, 1 for anything else */ 81 char *temp; /* pointer for string manipulation */ 82 83 /* 84 * Build an OPERATION_NOVELL_MGMT("get-server-version") request, 85 * which requires the following attributes: 86 * 87 * attributes-charset 88 * attributes-natural-language 89 * operation-name 90 * service-uri 91 */ 92 93 request = ippNew(); 94 95 request->request.op.operation_id = (ipp_op_t)OPERATION_NOVELL_MGMT; 96 request->request.op.request_id = 1; 97 98 language = cupsLangDefault(); 99 100 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 101 "attributes-charset", NULL, "utf-8"); 102 103 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 104 "attributes-natural-language", NULL, language->language); 105 106 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 107 "service-uri", NULL, serviceUri); 108 109 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 110 "operation-name", NULL, "get-server-version"); 111 112 /* 113 * Do the request and get back a response... 114 */ 115 116 if (((response = cupsDoRequest(http, request, "/ipp/")) == NULL) || 117 (response->request.status.status_code >= IPP_OK_CONFLICT)) 118 goto out; 119 120 if (((attr = ippFindAttribute(response, "server-version", 121 IPP_TAG_STRING)) != NULL)) { 122 if ((ver = strstr(attr->values[0].string.text, 123 NOVELL_SERVER_VERSION_STRING)) != NULL) { 124 ver += strlen(NOVELL_SERVER_VERSION_STRING); 125 /* 126 * Strangely, libcups stores a IPP_TAG_STRING (octet 127 * string) as a null-terminated string with no length 128 * even though it could be binary data with nulls in 129 * it. Luckily, in this case the value is not binary. 130 */ 131 serverVersion = strtol(ver, &vertmp, 10); 132 133 /* Check for not found, overflow or negative version */ 134 if ((ver == vertmp) || (serverVersion < 0)) 135 serverVersion = 0; 136 } 137 138 if ((os = strstr(attr->values[0].string.text, 139 NOVELL_SERVER_SYSNAME)) != NULL) { 140 os += strlen(NOVELL_SERVER_SYSNAME); 141 if ((temp = strchr(os,'<')) != NULL) 142 *temp = '\0'; 143 if (strcmp(os,NOVELL_SERVER_SYSNAME_NETWARE)) 144 osFlag = 1; /* 1 for non-NetWare systems */ 145 } 146 } 147 148 out: 149 if (response) 150 ippDelete(response); 151 152 if (language) 153 cupsLangFree(language); 154 155 if (osFlag == 0) 156 serverVersion *= -1; 157 158 return serverVersion; 159} 160 161 162static int iprint_cache_add_printer(http_t *http, 163 int reqId, 164 char* url) 165{ 166 ipp_t *request = NULL, /* IPP Request */ 167 *response = NULL; /* IPP Response */ 168 ipp_attribute_t *attr; /* Current attribute */ 169 cups_lang_t *language = NULL; /* Default language */ 170 char *name, /* printer-name attribute */ 171 *info, /* printer-info attribute */ 172 smb_enabled, /* smb-enabled attribute */ 173 secure; /* security-enabled attrib. */ 174 175 char *httpPath; /* path portion of the printer-uri */ 176 177 static const char *pattrs[] = /* Requested printer attributes */ 178 { 179 "printer-name", 180 "security-enabled", 181 "printer-info", 182 "smb-enabled" 183 }; 184 185 request = ippNew(); 186 187 request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; 188 request->request.op.request_id = reqId; 189 190 language = cupsLangDefault(); 191 192 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 193 "attributes-charset", NULL, "utf-8"); 194 195 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 196 "attributes-natural-language", NULL, language->language); 197 198 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, url); 199 200 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 201 "requested-attributes", 202 (sizeof(pattrs) / sizeof(pattrs[0])), 203 NULL, pattrs); 204 205 /* 206 * Do the request and get back a response... 207 */ 208 209 if ((httpPath = strstr(url,"://")) == NULL || 210 (httpPath = strchr(httpPath+3,'/')) == NULL) 211 { 212 ippDelete(request); 213 request = NULL; 214 goto out; 215 } 216 217 if ((response = cupsDoRequest(http, request, httpPath)) == NULL) { 218 ipp_status_t lastErr = cupsLastError(); 219 220 /* 221 * Ignore printers that cannot be queried without credentials 222 */ 223 if (lastErr == IPP_FORBIDDEN || 224 lastErr == IPP_NOT_AUTHENTICATED || 225 lastErr == IPP_NOT_AUTHORIZED) 226 goto out; 227 228 DEBUG(0,("Unable to get printer list - %s\n", 229 ippErrorString(lastErr))); 230 goto out; 231 } 232 233 for (attr = response->attrs; attr != NULL;) { 234 /* 235 * Skip leading attributes until we hit a printer... 236 */ 237 238 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 239 attr = attr->next; 240 241 if (attr == NULL) 242 break; 243 244 /* 245 * Pull the needed attributes from this printer... 246 */ 247 248 name = NULL; 249 info = NULL; 250 smb_enabled= 1; 251 secure = 0; 252 253 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) { 254 if (strcmp(attr->name, "printer-name") == 0 && 255 attr->value_tag == IPP_TAG_NAME) 256 name = attr->values[0].string.text; 257 258 if (strcmp(attr->name, "printer-info") == 0 && 259 (attr->value_tag == IPP_TAG_TEXT || 260 attr->value_tag == IPP_TAG_TEXTLANG)) 261 info = attr->values[0].string.text; 262 263 /* 264 * If the smb-enabled attribute is present and the 265 * value is set to 0, don't show the printer. 266 * If the attribute is not present, assume that the 267 * printer should show up 268 */ 269 if (!strcmp(attr->name, "smb-enabled") && 270 ((attr->value_tag == IPP_TAG_INTEGER && 271 !attr->values[0].integer) || 272 (attr->value_tag == IPP_TAG_BOOLEAN && 273 !attr->values[0].boolean))) 274 smb_enabled = 0; 275 276 /* 277 * If the security-enabled attribute is present and the 278 * value is set to 1, don't show the printer. 279 * If the attribute is not present, assume that the 280 * printer should show up 281 */ 282 if (!strcmp(attr->name, "security-enabled") && 283 ((attr->value_tag == IPP_TAG_INTEGER && 284 attr->values[0].integer) || 285 (attr->value_tag == IPP_TAG_BOOLEAN && 286 attr->values[0].boolean))) 287 secure = 1; 288 289 attr = attr->next; 290 } 291 292 /* 293 * See if we have everything needed... 294 * Make sure the printer is not a secure printer 295 * and make sure smb printing hasn't been explicitly 296 * disabled for the printer 297 */ 298 299 if (name != NULL && !secure && smb_enabled) 300 pcap_cache_add(name, info); 301 } 302 303 out: 304 if (response) 305 ippDelete(response); 306 return(0); 307} 308 309BOOL iprint_cache_reload(void) 310{ 311 http_t *http = NULL; /* HTTP connection to server */ 312 ipp_t *request = NULL, /* IPP Request */ 313 *response = NULL; /* IPP Response */ 314 ipp_attribute_t *attr; /* Current attribute */ 315 cups_lang_t *language = NULL; /* Default language */ 316 int i; 317 BOOL ret = False; 318 319 DEBUG(5, ("reloading iprint printcap cache\n")); 320 321 /* 322 * Make sure we don't ask for passwords... 323 */ 324 325 cupsSetPasswordCB(iprint_passwd_cb); 326 327 /* 328 * Try to connect to the server... 329 */ 330 331 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 332 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 333 iprint_server(), strerror(errno))); 334 goto out; 335 } 336 337 /* 338 * Build a OPERATION_NOVELL_LIST_PRINTERS request, which requires the following attributes: 339 * 340 * attributes-charset 341 * attributes-natural-language 342 */ 343 344 request = ippNew(); 345 346 request->request.op.operation_id = 347 (ipp_op_t)OPERATION_NOVELL_LIST_PRINTERS; 348 request->request.op.request_id = 1; 349 350 language = cupsLangDefault(); 351 352 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 353 "attributes-charset", NULL, "utf-8"); 354 355 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 356 "attributes-natural-language", NULL, language->language); 357 358 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 359 "ipp-server", NULL, "ippSrvr"); 360 361 /* 362 * Do the request and get back a response... 363 */ 364 365 if ((response = cupsDoRequest(http, request, "/ipp")) == NULL) { 366 DEBUG(0,("Unable to get printer list - %s\n", 367 ippErrorString(cupsLastError()))); 368 goto out; 369 } 370 371 for (attr = response->attrs; attr != NULL;) { 372 /* 373 * Skip leading attributes until we hit a printer... 374 */ 375 376 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 377 attr = attr->next; 378 379 if (attr == NULL) 380 break; 381 382 /* 383 * Pull the needed attributes from this printer... 384 */ 385 386 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) 387 { 388 if (strcmp(attr->name, "printer-name") == 0 && 389 (attr->value_tag == IPP_TAG_URI || 390 attr->value_tag == IPP_TAG_NAME || 391 attr->value_tag == IPP_TAG_TEXT || 392 attr->value_tag == IPP_TAG_NAMELANG || 393 attr->value_tag == IPP_TAG_TEXTLANG)) 394 { 395 for (i = 0; i<attr->num_values; i++) 396 { 397 char *url = attr->values[i].string.text; 398 if (!url || !strlen(url)) 399 continue; 400 iprint_cache_add_printer(http, i+2, url); 401 } 402 } 403 attr = attr->next; 404 } 405 } 406 407 ret = True; 408 409 out: 410 if (response) 411 ippDelete(response); 412 413 if (language) 414 cupsLangFree(language); 415 416 if (http) 417 httpClose(http); 418 419 return ret; 420} 421 422 423/* 424 * 'iprint_job_delete()' - Delete a job. 425 */ 426 427static int iprint_job_delete(const char *sharename, const char *lprm_command, struct printjob *pjob) 428{ 429 int ret = 1; /* Return value */ 430 http_t *http = NULL; /* HTTP connection to server */ 431 ipp_t *request = NULL, /* IPP Request */ 432 *response = NULL; /* IPP Response */ 433 cups_lang_t *language = NULL; /* Default language */ 434 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 435 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */ 436 437 438 DEBUG(5,("iprint_job_delete(%s, %p (%d))\n", sharename, pjob, pjob->sysjob)); 439 440 /* 441 * Make sure we don't ask for passwords... 442 */ 443 444 cupsSetPasswordCB(iprint_passwd_cb); 445 446 /* 447 * Try to connect to the server... 448 */ 449 450 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 451 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 452 iprint_server(), strerror(errno))); 453 goto out; 454 } 455 456 /* 457 * Build an IPP_CANCEL_JOB request, which uses the following 458 * attributes: 459 * 460 * attributes-charset 461 * attributes-natural-language 462 * printer-uri 463 * job-id 464 * requesting-user-name 465 */ 466 467 request = ippNew(); 468 469 request->request.op.operation_id = IPP_CANCEL_JOB; 470 request->request.op.request_id = 1; 471 472 language = cupsLangDefault(); 473 474 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 475 "attributes-charset", NULL, "utf-8"); 476 477 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 478 "attributes-natural-language", NULL, language->language); 479 480 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), sharename); 481 482 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); 483 484 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob); 485 486 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 487 NULL, pjob->user); 488 489 /* 490 * Do the request and get back a response... 491 */ 492 493 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", sharename); 494 495 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) { 496 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 497 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob, 498 ippErrorString(cupsLastError()))); 499 } else { 500 ret = 0; 501 } 502 } else { 503 DEBUG(0,("Unable to cancel job %d - %s\n", pjob->sysjob, 504 ippErrorString(cupsLastError()))); 505 } 506 507 out: 508 if (response) 509 ippDelete(response); 510 511 if (language) 512 cupsLangFree(language); 513 514 if (http) 515 httpClose(http); 516 517 return ret; 518} 519 520 521/* 522 * 'iprint_job_pause()' - Pause a job. 523 */ 524 525static int iprint_job_pause(int snum, struct printjob *pjob) 526{ 527 int ret = 1; /* Return value */ 528 http_t *http = NULL; /* HTTP connection to server */ 529 ipp_t *request = NULL, /* IPP Request */ 530 *response = NULL; /* IPP Response */ 531 cups_lang_t *language = NULL; /* Default language */ 532 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 533 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */ 534 535 536 DEBUG(5,("iprint_job_pause(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); 537 538 /* 539 * Make sure we don't ask for passwords... 540 */ 541 542 cupsSetPasswordCB(iprint_passwd_cb); 543 544 /* 545 * Try to connect to the server... 546 */ 547 548 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 549 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 550 iprint_server(), strerror(errno))); 551 goto out; 552 } 553 554 /* 555 * Build an IPP_HOLD_JOB request, which requires the following 556 * attributes: 557 * 558 * attributes-charset 559 * attributes-natural-language 560 * printer-uri 561 * job-id 562 * requesting-user-name 563 */ 564 565 request = ippNew(); 566 567 request->request.op.operation_id = IPP_HOLD_JOB; 568 request->request.op.request_id = 1; 569 570 language = cupsLangDefault(); 571 572 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 573 "attributes-charset", NULL, "utf-8"); 574 575 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 576 "attributes-natural-language", NULL, language->language); 577 578 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum)); 579 580 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); 581 582 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob); 583 584 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 585 NULL, pjob->user); 586 587 /* 588 * Do the request and get back a response... 589 */ 590 591 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum)); 592 593 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) { 594 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 595 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob, 596 ippErrorString(cupsLastError()))); 597 } else { 598 ret = 0; 599 } 600 } else { 601 DEBUG(0,("Unable to hold job %d - %s\n", pjob->sysjob, 602 ippErrorString(cupsLastError()))); 603 } 604 605 out: 606 if (response) 607 ippDelete(response); 608 609 if (language) 610 cupsLangFree(language); 611 612 if (http) 613 httpClose(http); 614 615 return ret; 616} 617 618 619/* 620 * 'iprint_job_resume()' - Resume a paused job. 621 */ 622 623static int iprint_job_resume(int snum, struct printjob *pjob) 624{ 625 int ret = 1; /* Return value */ 626 http_t *http = NULL; /* HTTP connection to server */ 627 ipp_t *request = NULL, /* IPP Request */ 628 *response = NULL; /* IPP Response */ 629 cups_lang_t *language = NULL; /* Default language */ 630 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 631 char httpPath[HTTP_MAX_URI]; /* path portion of the printer-uri */ 632 633 634 DEBUG(5,("iprint_job_resume(%d, %p (%d))\n", snum, pjob, pjob->sysjob)); 635 636 /* 637 * Make sure we don't ask for passwords... 638 */ 639 640 cupsSetPasswordCB(iprint_passwd_cb); 641 642 /* 643 * Try to connect to the server... 644 */ 645 646 if ((http = httpConnect(iprint_server(), ippPort())) == NULL) { 647 DEBUG(0,("Unable to connect to iPrint server %s - %s\n", 648 iprint_server(), strerror(errno))); 649 goto out; 650 } 651 652 /* 653 * Build an IPP_RELEASE_JOB request, which requires the following 654 * attributes: 655 * 656 * attributes-charset 657 * attributes-natural-language 658 * printer-uri 659 * job-id 660 * requesting-user-name 661 */ 662 663 request = ippNew(); 664 665 request->request.op.operation_id = IPP_RELEASE_JOB; 666 request->request.op.request_id = 1; 667 668 language = cupsLangDefault(); 669 670 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, 671 "attributes-charset", NULL, "utf-8"); 672 673 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, 674 "attributes-natural-language", NULL, language->language); 675 676 slprintf(uri, sizeof(uri) - 1, "ipp://%s/ipp/%s", iprint_server(), PRINTERNAME(snum)); 677 678 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); 679 680 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", pjob->sysjob); 681 682 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 683 NULL, pjob->user); 684 685 /* 686 * Do the request and get back a response... 687 */ 688 689 slprintf(httpPath, sizeof(httpPath) - 1, "/ipp/%s", PRINTERNAME(snum)); 690 691 if ((response = cupsDoRequest(http, request, httpPath)) != NULL) { 692 if (response->request.status.status_code >= IPP_OK_CONFLICT) { 693 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob, 694 ippErrorString(cupsLastError()))); 695 } else { 696 ret = 0; 697 } 698 } else { 699 DEBUG(0,("Unable to release job %d - %s\n", pjob->sysjob, 700 ippErrorString(cupsLastError()))); 701 } 702 703 out: 704 if (response) 705 ippDelete(response); 706 707 if (language) 708 cupsLangFree(language); 709 710 if (http) 711 httpClose(http); 712 713 return ret; 714} 715 716 717/* 718 * 'iprint_job_submit()' - Submit a job for printing. 719 */ 720 721static int iprint_job_submit(int snum, struct printjob *pjob) 722{ 723 int ret = 1; /* Return value */ 724 http_t *http = NULL; /* HTTP connection to server */ 725 ipp_t *request = NULL, /* IPP Request */ 726 *response = NULL; /* IPP Response */ 727 ipp_attribute_t *attr; /* Current attribute */ 728 cups_lang_t *language = NULL; /* Default language */ 729 char uri[HTTP_MAX_URI]; /* printer-uri attribute */ 730 char *clientname = NULL; /* hostname of client for job-originating-host attribute */ 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(); 783 if (strcmp(clientname, "UNKNOWN") == 0) { 784 clientname = client_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