1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 */ 27 28 /* $Id: in.lpd.c 170 2006-05-20 05:58:49Z njacobs $ */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <stdarg.h> 37 #include <string.h> 38 #include <errno.h> 39 #include <syslog.h> 40 #include <libintl.h> 41 #include <pwd.h> 42 #include <grp.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/socket.h> 46 #include <netinet/in.h> 47 #include <arpa/inet.h> 48 #include <netdb.h> 49 #include <sys/systeminfo.h> 50 51 #include <papi.h> 52 #include <uri.h> 53 #include "common.h" 54 55 #define ACK(fp) { (void) fputc('\0', fp); (void) fflush(fp); } 56 #define NACK(fp) { (void) fputc('\1', fp); (void) fflush(fp); } 57 58 /* 59 * This file contains the front-end of the BSD Print Protocol adaptor. This 60 * code assumes a BSD Socket interface to the networking side. 61 */ 62 63 static char * 64 remote_host_name(FILE *fp) 65 { 66 struct hostent *hp; 67 struct sockaddr_in6 peer; 68 socklen_t peer_len = sizeof (peer); 69 int fd = fileno(fp); 70 int error_num; 71 char myname[MAXHOSTNAMELEN], tmp_buf[INET6_ADDRSTRLEN]; 72 char *hostname; 73 74 /* who is our peer ? */ 75 if (getpeername(fd, (struct sockaddr *)&peer, &peer_len) < 0) { 76 if ((errno != ENOTSOCK) && (errno != EINVAL)) 77 return (NULL); 78 else 79 return (strdup("localhost")); 80 } 81 82 /* get their name or return a string containing their address */ 83 if ((hp = getipnodebyaddr((const char *)&peer.sin6_addr, 84 sizeof (struct in6_addr), AF_INET6, 85 &error_num)) == NULL) { 86 return (strdup(inet_ntop(peer.sin6_family, 87 &peer.sin6_addr, tmp_buf, sizeof (tmp_buf)))); 88 } 89 90 /* is it "localhost" ? */ 91 if (strcasecmp(hp->h_name, "localhost") == 0) 92 return (strdup("localhost")); 93 94 /* duplicate the name because gethostbyXXXX() is not reentrant */ 95 hostname = strdup(hp->h_name); 96 (void) sysinfo(SI_HOSTNAME, myname, sizeof (myname)); 97 98 /* is it from one of my addresses ? */ 99 if ((hp = getipnodebyname(myname, AF_INET6, AI_ALL|AI_V4MAPPED, 100 &error_num)) != NULL) { 101 struct in6_addr **tmp = (struct in6_addr **)hp->h_addr_list; 102 int i = 0; 103 104 while (tmp[i] != NULL) { 105 if (memcmp(tmp[i++], &peer.sin6_addr, hp->h_length) 106 == 0) { 107 free(hostname); 108 return (strdup("localhost")); 109 } 110 } 111 } 112 113 /* It must be someone else */ 114 return (hostname); 115 } 116 117 static void 118 fatal(FILE *fp, char *fmt, ...) 119 { 120 va_list ap; 121 122 va_start(ap, fmt); 123 vsyslog(LOG_DEBUG, fmt, ap); 124 vfprintf(fp, fmt, ap); 125 va_end(ap); 126 exit(1); 127 } 128 129 static void 130 cleanup(char ***files, char **cf) 131 { 132 if (*files != NULL) { 133 int i; 134 135 for (i = 0; (*files)[i] != NULL; i++) { 136 (void) unlink((*files)[i]); 137 free((*files)[i]); 138 } 139 free(*files); 140 *files = NULL; 141 } 142 143 if (*cf != NULL) { 144 free(*cf); 145 *cf = NULL; 146 } 147 } 148 149 static papi_attribute_t ** 150 parse_cf(papi_service_t svc, char *cf, char **files) 151 { 152 papi_attribute_t **list = NULL; 153 char previous = NULL, 154 *entry, 155 *s, 156 text[BUFSIZ]; 157 int count = 0, 158 copies_set = 0, 159 copies = 0; 160 161 for (entry = strtok(cf, "\n"); entry != NULL; 162 entry = strtok(NULL, "\n")) { 163 char *format = NULL; 164 165 /* count the copies */ 166 if ((entry[0] >= 'a') && (entry[0] <= 'z') && 167 (copies_set == 0) && (previous == entry[0])) 168 copies++; 169 else if ((previous >= 'a') && (previous <= 'z')) 170 copies_set = 1; 171 previous = entry[0]; 172 173 /* process the control message */ 174 switch (entry[0]) { 175 /* RFC-1179 options */ 176 case 'J': /* RFC-1179 Banner Job Name */ 177 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 178 "job-name", ++entry); 179 break; 180 case 'C': /* RFC-1179 Banner Class Name */ 181 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 182 "rfc-1179-class", ++entry); 183 break; 184 case 'L': /* RFC-1179 Banner toggle */ 185 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 186 "job-sheets", "standard"); 187 break; 188 case 'T': /* RFC-1179 Title (pr) */ 189 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 190 "pr-title", ++entry); 191 break; 192 case 'H': /* RFC-1179 Host */ 193 /* 194 * use the host as known by us, not by them 195 * 196 * papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 197 * "job-originating-host-name", ++entry); 198 */ 199 break; 200 case 'P': /* RFC-1179 User */ 201 ++entry; 202 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 203 "requesting-user-name", entry); 204 papiServiceSetUserName(svc, entry); 205 break; 206 case 'M': /* RFC-1179 Mail to User */ 207 papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 208 "rfc-1179-mail", 1); 209 break; 210 case 'W': /* RFC-1179 Width (pr) */ 211 papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 212 "pr-width", atoi(++entry)); 213 break; 214 case 'I': /* RFC-1179 Indent (pr) */ 215 papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 216 "pr-indent", atoi(++entry)); 217 break; 218 case 'N': /* RFC-1179 Filename */ 219 /* could have HPUX extension embedded */ 220 if (entry[1] != ' ') { /* real pathname */ 221 #ifdef DEBUG 222 papiAttributeListAddString(&list, 223 PAPI_ATTR_EXCL, 224 "flist", ++entry); 225 #endif 226 } else if (entry[2] == 'O') /* HPUX lp -o options */ 227 papiAttributeListFromString(&list, 228 PAPI_ATTR_APPEND, ++entry); 229 break; 230 case 'U': /* RFC-1179 Unlink */ 231 break; /* ignored */ 232 case '1': /* RFC-1179 TROFF Font R */ 233 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 234 "rfc-1179-font-r", ++entry); 235 break; 236 case '2': /* RFC-1179 TROFF Font I */ 237 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 238 "rfc-1179-font-i", ++entry); 239 break; 240 case '3': /* RFC-1179 TROFF Font B */ 241 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 242 "rfc-1179-font-b", ++entry); 243 break; 244 case '4': /* RFC-1179 TROFF Font S */ 245 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 246 "rfc-1179-font-s", ++entry); 247 break; 248 case 'f': /* RFC-1179 ASCII file (print) */ 249 format = "text/plain"; 250 if (is_postscript(files[0]) == 1) 251 format = "application/postscript"; 252 break; 253 case 'l': /* RFC-1179 CATV file (print) */ 254 format = "application/octet-stream"; 255 if (is_postscript(files[0]) == 1) 256 format = "application/postscript"; 257 break; 258 case 'o': /* RFC-1179 Postscript file (print) */ 259 format = "application/postscript"; 260 break; 261 case 'p': /* RFC-1179 PR file (print) */ 262 format = "application/x-pr"; 263 papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL, 264 "pr-filter", 1); 265 break; 266 case 't': /* RFC-1179 TROFF file (print) */ 267 format = "application/x-troff"; 268 break; 269 case 'n': /* RFC-1179 DITROFF file (print) */ 270 format = "application/x-ditroff"; 271 break; 272 case 'd': /* RFC-1179 DVI file (print) */ 273 format = "application/x-dvi"; 274 break; 275 case 'g': /* RFC-1179 GRAPH file (print) */ 276 format = "application/x-plot"; 277 break; 278 case 'c': /* RFC-1179 CIF file (print) */ 279 format = "application/x-cif"; 280 break; 281 case 'v': /* RFC-1179 RASTER file (print) */ 282 format = "application/x-raster"; 283 break; 284 case 'r': /* RFC-1179 FORTRAN file (print) */ 285 format = "application/x-fortran"; 286 break; 287 /* Sun Solaris Extensions */ 288 case 'O': 289 ++entry; 290 do { 291 if (*entry != '"') 292 text[count++] = *entry; 293 } while (*entry++); 294 papiAttributeListFromString(&list, PAPI_ATTR_APPEND, 295 text); 296 break; 297 case '5': 298 ++entry; 299 switch (entry[0]) { 300 case 'f': /* Solaris form */ 301 papiAttributeListAddString(&list, 302 PAPI_ATTR_EXCL, 303 "form", ++entry); 304 break; 305 case 'H': /* Solaris handling */ 306 ++entry; 307 if (strcasecmp(entry, "hold") == 0) 308 papiAttributeListAddString(&list, 309 PAPI_ATTR_EXCL, 310 "job-hold-until", "indefinite"); 311 else if (strcasecmp(entry, "release") == 0) 312 papiAttributeListAddString(&list, 313 PAPI_ATTR_EXCL, 314 "job-hold-until", "no-hold"); 315 else if (strcasecmp(entry, "immediate") == 0) 316 papiAttributeListAddInteger(&list, 317 PAPI_ATTR_EXCL, 318 "job-priority", 100); 319 else 320 papiAttributeListAddString(&list, 321 PAPI_ATTR_EXCL, 322 "job-hold-until", entry); 323 break; 324 case 'p': /* Solaris notification */ 325 papiAttributeListAddBoolean(&list, 326 PAPI_ATTR_EXCL, "rfc-1179-mail", 1); 327 break; 328 case 'P': /* Solaris page list */ 329 papiAttributeListAddString(&list, 330 PAPI_ATTR_EXCL, 331 "page-ranges", ++entry); 332 break; 333 case 'q': { /* Solaris priority */ 334 int i = atoi(optarg); 335 336 i = 99 * (39 - i) / 39 + 1; 337 if ((i < 1) || (i > 100)) 338 i = 50; 339 papiAttributeListAddInteger(&list, 340 PAPI_ATTR_EXCL, "priority", i); 341 } 342 break; 343 case 'S': /* Solaris character set */ 344 papiAttributeListAddString(&list, 345 PAPI_ATTR_EXCL, "lp-charset", 346 ++entry); 347 break; 348 case 'T': /* Solaris type */ 349 format = lp_type_to_mime_type(++entry); 350 break; 351 case 'y': /* Solaris mode */ 352 papiAttributeListAddString(&list, 353 PAPI_ATTR_APPEND, "lp-modes", ++entry); 354 break; 355 default: 356 syslog(LOG_INFO|LOG_DEBUG, 357 "Warning: cf message (%s) ignored", 358 entry); 359 break; 360 } 361 break; 362 /* Undefined Extensions: SCO, Ultrix, AIX, ... */ 363 364 default: 365 syslog(LOG_INFO|LOG_DEBUG, 366 "Warning: cf message (%s) ignored", entry); 367 break; 368 } 369 370 if (format != NULL) 371 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 372 "document-format", format); 373 } 374 375 papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, 376 "copies", ++copies); 377 papiAttributeListAddString(&list, PAPI_ATTR_EXCL, 378 "job-sheets", "none"); 379 380 return (list); 381 } 382 383 static papi_status_t 384 submit_job(papi_service_t svc, FILE *ifp, char *printer, char *cf, char **files) 385 { 386 papi_attribute_t **list = NULL; 387 papi_status_t status; 388 papi_job_t job = NULL; 389 char *format = ""; 390 391 if ((list = parse_cf(svc, cf, files)) != NULL) { 392 /* use the host as known by us, not by them */ 393 char *host = remote_host_name(ifp); 394 395 if (host != NULL) { 396 papiAttributeListAddString(&list, PAPI_ATTR_REPLACE, 397 "job-originating-host-name", host); 398 free(host); 399 } 400 } 401 402 status = papiJobSubmit(svc, printer, list, NULL, files, &job); 403 syslog(LOG_DEBUG, "submit: %s", papiStatusString(status)); 404 if (status != PAPI_OK) { 405 char *tmp = papiServiceGetStatusMessage(svc); 406 407 syslog(LOG_DEBUG, "submit-detail: %s", tmp ? tmp : "none"); 408 } 409 papiJobFree(job); 410 411 return (status); 412 } 413 414 static char * 415 receive_control_file(papi_service_t svc, FILE *ifp, FILE *ofp, int size) 416 { 417 char *ptr, *cf_data; 418 419 if ((ptr = cf_data = calloc(1, size + 1)) == NULL) { 420 NACK(ofp); 421 return (NULL); 422 } else 423 ACK(ofp); 424 425 while (size > 0) { 426 int rc; 427 428 if (((rc = fread(ptr, 1, size, ifp)) == 0) && 429 (feof(ifp) != 0)) { 430 free(cf_data); 431 return (NULL); 432 } else { 433 ptr += rc; 434 size -= rc; 435 } 436 } 437 syslog(LOG_DEBUG, "cf_data(%s)", cf_data); 438 439 if (fgetc(ifp) != 0) { 440 free(cf_data); 441 return (NULL); 442 } 443 ACK(ofp); 444 445 return (cf_data); 446 } 447 448 static char * 449 receive_data_file(FILE *ifp, FILE *ofp, int size) 450 { 451 char file[] = "lpdXXXXXX"; 452 char buf[BUFSIZ]; 453 int fd; 454 455 if ((fd = mkstemp(file)) < 0) { 456 NACK(ofp); 457 return (NULL); 458 } else 459 ACK(ofp); 460 461 while (size > 0) { 462 int rc = ((size > BUFSIZ) ? BUFSIZ : size); 463 464 if (((rc = fread(buf, 1, rc, ifp)) == 0) && 465 (feof(ifp) != 0)) { 466 close(fd); 467 unlink(file); 468 return (NULL); 469 } else { 470 char *ptr = buf; 471 472 while (rc > 0) { 473 int wrc = write(fd, ptr, rc); 474 475 if (wrc < 0) { 476 close(fd); 477 unlink(file); 478 return(NULL); 479 } 480 481 ptr += wrc; 482 size -= wrc; 483 rc -= wrc; 484 } 485 } 486 } 487 close(fd); 488 if (fgetc(ifp) != 0) { 489 unlink(file); 490 return (NULL); 491 } 492 ACK(ofp); 493 494 return (strdup(file)); 495 } 496 497 static papi_status_t 498 berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp, char *printer) 499 { 500 papi_status_t status = PAPI_OK; 501 char *file, **files = NULL; /* the job data files */ 502 char *cf = NULL; 503 char buf[BUFSIZ]; 504 505 while (fgets(buf, sizeof (buf), ifp) != NULL) { 506 int size; 507 508 syslog(LOG_DEBUG, "XFER CMD: (%d)%s\n", buf[0], &buf[1]); 509 #ifdef DEBUG /* translate [1-3]... messages to \[1-3] to run by hand */ 510 if ((buf[0] > '0') && (buf[0] < '4')) 511 buf[0] -= '0'; 512 #endif 513 switch (buf[0]) { 514 case 0x01: /* Abort */ 515 cleanup(&files, &cf); 516 break; 517 case 0x02: { /* Receive control file */ 518 cf = receive_control_file(svc, ifp, ofp, atoi(&buf[1])); 519 if (cf == NULL) { 520 cleanup(&files, &cf); 521 return (PAPI_BAD_REQUEST); 522 } else if (files != NULL) { 523 status = submit_job(svc, ifp, printer, cf, 524 files); 525 cleanup(&files, &cf); 526 } 527 } 528 break; 529 case 0x03: { /* Receive data file */ 530 file = receive_data_file(ifp, ofp, atoi(&buf[1])); 531 if (file == NULL) { 532 cleanup(&files, &cf); 533 return (PAPI_TEMPORARY_ERROR); 534 } 535 list_append(&files, file); 536 } 537 break; 538 default: 539 cleanup(&files, &cf); 540 fatal(ofp, "protocol screwup"); 541 break; 542 } 543 } 544 545 if ((cf != NULL) && (files != NULL)) 546 status = submit_job(svc, ifp, printer, cf, files); 547 548 cleanup(&files, &cf); 549 550 return (status); 551 } 552 553 static papi_status_t 554 berkeley_transfer_files(papi_service_t svc, FILE *ifp, FILE *ofp, 555 char *printer) 556 { 557 papi_status_t status; 558 papi_printer_t p = NULL; 559 char *keys[] = { "printer-is-accepting-jobs", NULL }; 560 561 status = papiPrinterQuery(svc, printer, keys, NULL, &p); 562 if ((status == PAPI_OK) && (p != NULL)) { 563 papi_attribute_t **attrs = papiPrinterGetAttributeList(p); 564 char accepting = PAPI_FALSE; 565 566 papiAttributeListGetBoolean(attrs, NULL, 567 "printer-is-accepting-jobs", &accepting); 568 569 if (accepting == PAPI_TRUE) { 570 ACK(ofp); 571 status = berkeley_receive_files(svc, ifp, ofp, printer); 572 } else 573 NACK(ofp); 574 575 papiPrinterFree(p); 576 } else 577 NACK(ofp); 578 579 return (status); 580 } 581 582 static int 583 cyclical_service_check(char *svc_name) 584 { 585 papi_attribute_t **list; 586 char buf[BUFSIZ]; 587 uri_t *uri = NULL; 588 char *s = NULL; 589 590 /* was there a printer? */ 591 if (svc_name == NULL) 592 return (0); 593 594 if ((list = getprinterbyname(svc_name, NULL)) == NULL) 595 return (0); /* if it doesnt' resolve, we will fail later */ 596 597 papiAttributeListGetString(list, NULL, "printer-uri-supported", &s); 598 if ((s == NULL) || (strcasecmp(svc_name, s) != 0)) 599 return (0); /* they don't match */ 600 601 /* is it in uri form? */ 602 if (uri_from_string(s, &uri) < 0) 603 return (0); 604 605 if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) { 606 uri_free(uri); 607 return (0); 608 } 609 610 /* is it in lpd form? */ 611 if (strcasecmp(uri->scheme, "lpd") != 0) { 612 uri_free(uri); 613 return (0); 614 } 615 616 /* is it the local host? */ 617 sysinfo(SI_HOSTNAME, buf, sizeof (buf)); 618 if ((strcasecmp(uri->host, "localhost") != 0) && 619 (strcasecmp(uri->host, buf) != 0)) { 620 uri_free(uri); 621 return (0); 622 } 623 624 uri_free(uri); 625 return (1); 626 } 627 628 629 /* 630 * This is the entry point for this program. The program takes the 631 * following options: 632 * (none) 633 */ 634 int 635 main(int ac, char *av[]) 636 { 637 papi_status_t status; 638 papi_service_t svc = NULL; 639 papi_encryption_t encryption = PAPI_ENCRYPT_NEVER; 640 FILE *ifp = stdin, 641 *ofp = stdout; 642 int c; 643 char buf[BUFSIZ], 644 **args, 645 *printer, 646 *run_dir = "/var/run/in.lpd", 647 *run_user = NULL; 648 struct passwd *pw = NULL; 649 650 (void) chdir("/tmp"); /* run in /tmp by default */ 651 openlog("bsd-gw", LOG_PID, LOG_LPR); 652 653 while ((c = getopt(ac, av, "Ed:u:")) != EOF) 654 switch (c) { 655 case 'E': 656 encryption = PAPI_ENCRYPT_ALWAYS; 657 break; 658 case 'd': /* run where they tell you */ 659 run_dir = optarg; 660 break; 661 case 'u': /* run as */ 662 run_user = optarg; 663 break; 664 default: 665 ; 666 } 667 668 if (run_user != NULL) /* get the requested user info */ 669 pw = getpwnam(run_user); 670 671 if (run_dir != NULL) { /* setup the run_dir */ 672 (void) mkdir(run_dir, 0700); 673 if (pw != NULL) 674 (void) chown(run_dir, pw->pw_uid, pw->pw_gid); 675 } 676 677 if (pw != NULL) { /* run as the requested user */ 678 syslog(LOG_DEBUG, "name: %s, uid: %d, gid: %d", 679 pw->pw_name, pw->pw_uid, pw->pw_gid); 680 initgroups(pw->pw_name, pw->pw_gid); 681 setgid(pw->pw_gid); 682 setuid(pw->pw_uid); 683 } 684 685 if (run_dir != NULL) /* move to the run_dir */ 686 if (chdir(run_dir) < 0) { 687 syslog(LOG_DEBUG, "failed to chdir(%s)", run_dir); 688 exit(1); 689 } 690 691 syslog(LOG_DEBUG, "$CWD = %s", getwd(NULL)); 692 693 if (fgets(buf, sizeof (buf), ifp) == NULL) { 694 if (feof(ifp) == 0) 695 syslog(LOG_ERR, "Error reading from connection: %s", 696 strerror(errno)); 697 exit(1); 698 } 699 700 syslog(LOG_DEBUG, "CMD: (%d)%s\n", buf[0], &buf[1]); 701 702 #ifdef DEBUG /* translate [1-5]... messages to \[1-5] to run by hand */ 703 if ((buf[0] > '0') && (buf[0] < '6')) 704 buf[0] -= '0'; 705 #endif 706 707 if ((buf[0] < 1) || (buf[0] > 5)) { 708 fatal(ofp, "Invalid protocol request (%d): %c%s\n", 709 buf[0], buf[0], buf); 710 exit(1); 711 } 712 713 args = strsplit(&buf[1], "\t\n "); 714 printer = *args++; 715 716 if (printer == NULL) { 717 fatal(ofp, "Can't determine requested printer"); 718 exit(1); 719 } 720 721 if (cyclical_service_check(printer) != 0) { 722 fatal(ofp, "%s is cyclical\n", printer); 723 exit(1); 724 } 725 726 status = papiServiceCreate(&svc, printer, NULL, NULL, NULL, 727 encryption, NULL); 728 if (status != PAPI_OK) { 729 fatal(ofp, "Failed to contact service for %s: %s\n", printer, 730 verbose_papi_message(svc, status)); 731 exit(1); 732 } 733 734 /* 735 * Trusted Solaris can't be trusting of intermediaries. Pass 736 * the socket connection to the print service to retrieve the 737 * sensativity label off of a multi-level port. 738 */ 739 (void) papiServiceSetPeer(svc, fileno(ifp)); 740 741 switch (buf[0]) { 742 case '\1': /* restart printer */ 743 ACK(ofp); /* there is no equivalent */ 744 break; 745 case '\2': /* transfer job(s) */ 746 status = berkeley_transfer_files(svc, ifp, ofp, printer); 747 break; 748 case '\3': /* show queue (short) */ 749 case '\4': { /* show queue (long) */ 750 int count; 751 752 for (count = 0; args[count] != 0; count++); 753 754 berkeley_queue_report(svc, ofp, printer, buf[0], count, args); 755 } 756 break; 757 case '\5': { /* cancel job(s) */ 758 char *user = *args++; 759 char *host = remote_host_name(ifp); 760 int count; 761 762 if (host != NULL) { 763 char buf[BUFSIZ]; 764 765 snprintf(buf, sizeof (buf), "%s@%s", user, host); 766 status = papiServiceSetUserName(svc, buf); 767 } else 768 status = papiServiceSetUserName(svc, user); 769 770 for (count = 0; args[count] != 0; count++); 771 772 berkeley_cancel_request(svc, ofp, printer, count, args); 773 } 774 break; 775 default: 776 fatal(ofp, "unsupported protocol request (%c), %s", 777 buf[0], &buf[1]); 778 } 779 780 (void) fflush(ofp); 781 782 syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s", 783 buf[0], printer, papiStatusString(status)); 784 if (status != PAPI_OK) 785 syslog(LOG_DEBUG, "detail: %s", 786 verbose_papi_message(svc, status)); 787 788 papiServiceDestroy(svc); 789 790 return (0); 791 } 792