home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / LINUX_PC.TAR / pcnfsd_linux2 / pcnfsd_print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-26  |  38.5 KB  |  1,641 lines

  1. /* RE_SID: @(%)/tmp_mnt/vol/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_print.c 1.12 93/01/29 17:53:03 SMI */
  2. /*
  3. **=====================================================================
  4. ** Copyright (c) 1986-1993 by Sun Microsystems, Inc.
  5. **    @(#)pcnfsd_print.c    1.12    1/29/93
  6. **=====================================================================
  7. */
  8. #include "common.h"
  9. /*
  10. **=====================================================================
  11. **             I N C L U D E   F I L E   S E C T I O N                *
  12. **                                                                    *
  13. ** If your port requires different include files, add a suitable      *
  14. ** #define in the customization section, and make the inclusion or    *
  15. ** exclusion of the files conditional on this.                        *
  16. **=====================================================================
  17. */
  18. #include "pcnfsd.h"
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <pwd.h>
  22. #include <ctype.h>
  23. #include <sys/file.h>
  24. #include <signal.h>
  25. #include <sys/stat.h>
  26. #include <sys/ioctl.h>
  27. #include <netdb.h>
  28. #include <errno.h>
  29. #include <string.h>
  30.  
  31. #ifdef ISC_2_0
  32. #include <sys/fcntl.h>
  33. #include <sys/wait.h>
  34. #endif ISC_2_0
  35.  
  36. #ifdef SHADOW_SUPPORT
  37. #include <shadow.h>
  38. #endif SHADOW_SUPPORT
  39.  
  40. /*
  41. **---------------------------------------------------------------------
  42. ** Other #define's 
  43. **---------------------------------------------------------------------
  44. */
  45. #ifndef MAXPATHLEN
  46. #define MAXPATHLEN 1024
  47. #endif
  48.  
  49. #ifndef SPOOLDIR
  50. #define SPOOLDIR        "/var/spool/pcnfs"
  51. #endif SPOOLDIR
  52.  
  53. /*
  54. ** The following defintions give the maximum time allowed for
  55. ** an external command to run (in seconds)
  56. */
  57. #define MAXTIME_FOR_PRINT    10
  58. #define MAXTIME_FOR_QUEUE    10
  59. #define MAXTIME_FOR_CANCEL    10
  60. #define MAXTIME_FOR_STATUS    10
  61.  
  62. #define QMAX 50
  63.  
  64. /*
  65. ** The following is derived from ucb/lpd/displayq.c
  66. */
  67. #define SIZECOL 62
  68. #define FILECOL 24
  69.  
  70. extern void     scramble();
  71. extern void     *grab();
  72. extern int      suspicious();
  73. extern void     run_ps630();
  74. extern char    *crypt();
  75. extern FILE    *su_popen();
  76. extern int      su_pclose();
  77. extern char    *my_strdup();
  78. int             build_pr_list();
  79. void        mon_printers();
  80. char            *map_printer_name();
  81. char           *expand_alias();
  82. void           *grab();
  83. void            free_pr_list_item();
  84. void            free_pr_queue_item();
  85. pr_list        list_virtual_printers();
  86.  
  87. /*
  88. **---------------------------------------------------------------------
  89. **                       Misc. variable definitions
  90. **---------------------------------------------------------------------
  91. */
  92.  
  93. extern int      errno;
  94. extern int    interrupted;    /* in pcnfsd_misc.c */
  95. struct stat     statbuf;
  96. char            pathname[MAXPATHLEN];
  97. char            new_pathname[MAXPATHLEN];
  98. char            sp_name[MAXPATHLEN] = SPOOLDIR;
  99. char            tempstr[256];
  100. char            delims[] = " \t\r\n:()";
  101.  
  102. pr_list         printers = NULL;
  103. pr_queue        queue = NULL;
  104.  
  105. #ifdef ACCEPT_BSD_PR_NAMES
  106. pr_list         alt_printers = NULL;
  107. #endif ACCEPT_BSD_PR_NAMES
  108.  
  109. /*
  110. **=====================================================================
  111. **                      C O D E   S E C T I O N                       *
  112. **=====================================================================
  113. **
  114. **=====================================================================
  115. **                    C A V E A T   L E C T O R  ! ! ! !              *
  116. **                                                                    *
  117. ** The following code relies upon the definition or non-definition of *
  118. ** a set of manifest constants which control whether BSD or SVR4      *
  119. ** rules should be adopted. It's not as simple as it might be,        *
  120. ** because certain OS's may support a mixture of facilities (or in    *
  121. ** some cases a mechanism may be broken).                             *
  122. ** This mechanism also allows for the addition of new styles.         *
  123. **                                                                    *
  124. ** Within each line, only one symbol should be defined.               *
  125. **                                                                    *
  126. **  SVR4_STYLE_PRINT     BSD_STYLE_PRINT                              *
  127. **  SVR4_STYLE_PR_LIST   BSD_STYLE_PR_LIST                            *
  128. **  SVR4_STYLE_QUEUE     BSD_STYLE_QUEUE                              *
  129. **  SVR4_STYLE_CANCEL    BSD_STYLE_CANCEL                             *
  130. **  SVR4_STYLE_STATUS    BSD_STYLE_STATUS                             *
  131. **  SVR4_STYLE_MONITOR   BSD_STYLE_MONITOR                            *
  132. **                                                                    *
  133. ** The actual per-OS definitions are given in common.h, and are       *
  134. ** based on the definition of OSVER_xxx in the Makefile             *
  135. **=====================================================================
  136. */
  137. #ifdef SUNOS_403C
  138.  
  139. /*
  140.  * This is strstr() as in SysV and later SunOS's
  141.  */
  142. char *strstr(target, pattern)
  143. char *target;
  144. char *pattern;
  145. {
  146.     int n;
  147.     char *cp;
  148.     if(pattern == NULL || target == NULL)
  149.         return NULL;
  150.     n = strlen(pattern);
  151.     for(cp = target; cp++; *cp) {
  152.         if(strlen(cp) < n)
  153.             break;
  154.         if(strncmp(cp, pattern, n) == 0)
  155.             return cp;
  156.     }
  157.     return NULL;
  158. }
  159.     
  160. #endif SUNOS_403C
  161.  
  162.  
  163.  
  164. /*
  165. ** valid_pr
  166. **
  167. ** true if a printer name is valid
  168. */
  169.  
  170. int
  171. valid_pr(pr)
  172. char *pr;
  173. {
  174. char *p;
  175. pr_list curr;
  176.  
  177.     mon_printers();
  178.  
  179.     if(printers == NULL)
  180.         build_pr_list();
  181.  
  182.     if(printers == NULL)
  183.         return(0); /* can't tell - assume it's bad */
  184.  
  185.     p = map_printer_name(pr);
  186.     if (p == NULL)
  187.         return(1);    /* must be ok if maps to NULL! */
  188.     curr = printers;
  189.     while(curr) {
  190.         if(!strcmp(p, curr->pn))
  191.             return(1);
  192.         curr = curr->pr_next;
  193.     }
  194.  
  195. #ifdef ACCEPT_BSD_PR_NAMES
  196.     if(alt_printers == NULL)
  197.         return(0);    /* No alt list    */
  198.  
  199.     curr = alt_printers;
  200.     while(curr) {
  201.         if(!strcmp(p, curr->pn))
  202.             return(1);
  203.         curr = curr->pr_next;
  204.     }
  205. #endif ACCEPT_BSD_PR_NAMES
  206.         
  207.     return(0);
  208. }
  209.  
  210.  
  211. /*
  212. ** pr_init
  213. **
  214. ** create a spool directory for a client if necessary and return the info
  215. */
  216. pirstat
  217. pr_init(sys, pr, sp)
  218. char *sys;
  219. char *pr;
  220. char**sp;
  221. {
  222. int    dir_mode = 0777;
  223. int rc;
  224.  
  225.     *sp = &pathname[0];
  226.     pathname[0] = '\0';
  227.  
  228.     if(suspicious(sys) || suspicious(pr))
  229.         return(PI_RES_FAIL);
  230.  
  231.     /* get pathname of current directory and return to client */
  232.  
  233.     (void)sprintf(pathname,"%s/%s",sp_name, sys);
  234.     (void)mkdir(sp_name, dir_mode);    /* ignore the return code */
  235.     (void)chmod(sp_name, dir_mode);
  236.     rc = mkdir(pathname, dir_mode);    /* DON'T ignore this return code */
  237.     if((rc < 0 && errno != EEXIST) ||
  238.        (chmod(pathname, dir_mode) != 0) ||
  239.        (stat(pathname, &statbuf) != 0) ||
  240.        !(statbuf.st_mode & S_IFDIR)) {
  241.        (void)sprintf(tempstr,
  242.                  "rpc.pcnfsd: unable to set up spool directory %s\n",
  243.                pathname);
  244.             msg_out(tempstr);
  245.         pathname[0] = '\0';    /* null to tell client bad vibes */
  246.         return(PI_RES_FAIL);
  247.         }
  248.      if (!valid_pr(pr)) 
  249.            {
  250.         pathname[0] = '\0';    /* null to tell client bad vibes */
  251.         return(PI_RES_NO_SUCH_PRINTER);
  252.         } 
  253.     return(PI_RES_OK);
  254. }
  255.  
  256.  
  257.  
  258. /*
  259. ** pr_start2
  260. **
  261. ** start a print job
  262. */
  263. psrstat
  264. pr_start2(system, pr, user, fname, opts, id)
  265. char *system;
  266. char *pr;
  267. char *user;
  268. char *fname;
  269. char *opts;
  270. char **id;
  271. {
  272. char            snum[20];
  273. static char     req_id[256];
  274. char            cmdbuf[256];
  275. char            resbuf[256];
  276. FILE *fd;
  277. int i;
  278. char *xcmd;
  279. char *cp;
  280. int failed = 0;
  281.  
  282.     *id = &req_id[0];
  283.     req_id[0] = '\0';
  284.  
  285.  
  286.     if(suspicious(system) || 
  287.         suspicious(pr) ||
  288.         suspicious(user) ||
  289.         suspicious(fname))
  290.         return(PS_RES_FAIL);
  291.  
  292.     (void)sprintf(pathname,"%s/%s/%s",sp_name,
  293.                              system,
  294.                              fname);    
  295.  
  296.  
  297.     if (stat(pathname, &statbuf)) 
  298.            {
  299.        /*
  300.            **-----------------------------------------------------------------
  301.        ** We can't stat the file. Let's try appending '.spl' and
  302.        ** see if it's already in progress.
  303.            **-----------------------------------------------------------------
  304.        */
  305.  
  306.        (void)strcat(pathname, ".spl");
  307.        if (stat(pathname, &statbuf)) 
  308.           {
  309.           /*
  310.               **----------------------------------------------------------------
  311.           ** It really doesn't exist.
  312.               **----------------------------------------------------------------
  313.           */
  314.  
  315.  
  316.           return(PS_RES_NO_FILE);
  317.           }
  318.           /*
  319.               **-------------------------------------------------------------
  320.           ** It is already on the way.
  321.               **-------------------------------------------------------------
  322.           */
  323.  
  324.  
  325.         return(PS_RES_ALREADY);
  326.          }
  327.  
  328.     if (statbuf.st_size == 0) 
  329.        {
  330.        /*
  331.            **-------------------------------------------------------------
  332.        ** Null file - don't print it, just kill it.
  333.            **-------------------------------------------------------------
  334.        */
  335.        (void)unlink(pathname);
  336.  
  337.         return(PS_RES_NULL);
  338.         }
  339.      /*
  340.          **-------------------------------------------------------------
  341.      ** The file is real, has some data, and is not already going out.
  342.      ** We rename it by appending '.spl' and exec "lpr" to do the
  343.      ** actual work.
  344.          **-------------------------------------------------------------
  345.      */
  346.     (void)strcpy(new_pathname, pathname);
  347.     (void)strcat(new_pathname, ".spl");
  348.  
  349.     /*
  350.         **-------------------------------------------------------------
  351.     ** See if the new filename exists so as not to overwrite it.
  352.         **-------------------------------------------------------------
  353.     */
  354.  
  355.  
  356.     if (!stat(new_pathname, &statbuf)) 
  357.        {
  358.        (void)strcpy(new_pathname, pathname);  /* rebuild a new name */
  359.        (void)sprintf(snum, "%d", rand());      /* get some number */
  360.        (void)strncat(new_pathname, snum, 3);
  361.        (void)strcat(new_pathname, ".spl");      /* new spool file */
  362.         }
  363.     if (rename(pathname, new_pathname)) 
  364.        {
  365.        /*
  366.            **---------------------------------------------------------------
  367.        ** Should never happen.
  368.            **---------------------------------------------------------------
  369.            */
  370.        (void)sprintf(tempstr, "rpc.pcnfsd: spool file rename (%s->%s) failed.\n",
  371.             pathname, new_pathname);
  372.                 msg_out(tempstr);
  373.         return(PS_RES_FAIL);
  374.         }
  375.  
  376.         if (*opts == 'd') 
  377.                {
  378.            /*
  379.                    **------------------------------------------------------
  380.            ** This is a Diablo print stream. Apply the ps630
  381.            ** filter with the appropriate arguments.
  382.                    **------------------------------------------------------
  383.            */
  384.            (void)run_ps630(new_pathname, opts);
  385.            }
  386.         /*
  387.         ** Try to match to an aliased printer
  388.         */
  389.         xcmd = expand_alias(pr, new_pathname, user, system);
  390.             /*
  391.                 **----------------------------------------------------------
  392.             **  Use the copy option so we can remove the orignal spooled
  393.             **  nfs file from the spool directory.
  394.                 **----------------------------------------------------------
  395.             */
  396.         if(!xcmd) {
  397. #ifdef BSD_STYLE_PRINT
  398. #ifdef BSD386
  399.             sprintf(cmdbuf, "/usr/bin/lpr -P%s -C%s -J%s %s",
  400.                 pr, system, user, new_pathname);
  401. #else
  402.             sprintf(cmdbuf, "/usr/ucb/lpr -P%s -C%s -J%s %s",
  403.                 pr, system, user, new_pathname);
  404. #endif BSD386
  405. #endif BSD_STYLE_PRINT
  406. #ifdef SVR4_STYLE_PRINT
  407.             sprintf(cmdbuf, "/usr/bin/lp -c -d%s %s",
  408.                 pr, new_pathname);
  409. #endif SVR4_STYLE_PRINT
  410.             xcmd = cmdbuf;
  411.         }
  412.         if ((fd = su_popen(user, xcmd, MAXTIME_FOR_PRINT)) == NULL) {
  413.             msg_out("rpc.pcnfsd: su_popen failed");
  414.             return(PS_RES_FAIL);
  415.         }
  416.         req_id[0] = '\0';    /* asume failure */
  417.         while(fgets(resbuf, 255, fd) != NULL) {
  418.             i = strlen(resbuf);
  419.             if(i)
  420.                 resbuf[i-1] = '\0'; /* trim NL */
  421.             if(!strncmp(resbuf, "request id is ", 14))
  422.                 /* New - just the first word is needed */
  423.                 strcpy(req_id, strtok(&resbuf[14], delims));
  424.             else if (strembedded("disabled", resbuf))
  425.                 failed = 1;
  426.         }
  427.         if(su_pclose(fd) == 255)
  428.             msg_out("rpc.pcnfsd: su_pclose alert");
  429.         (void)unlink(new_pathname);
  430.         return((failed | interrupted)? PS_RES_FAIL : PS_RES_OK);
  431. }
  432.  
  433. /*
  434. ** Decide whether to blow away the printers list based
  435. ** on a change to a specified file or directory.
  436. **
  437. */
  438. void
  439. mon_printers()
  440. {
  441.     static struct stat buf;
  442.     static time_t    old_mtime = (time_t)0;
  443. #ifdef SVR4_STYLE_MONITOR
  444.     char *mon_path = "/etc/lp/printers";
  445. #endif
  446. #ifdef BSD_STYLE_MONITOR
  447.     char *mon_path = "/etc/printcap";
  448. #endif
  449.     if(stat(mon_path, &buf) == -1)
  450.         return;
  451.     if(old_mtime != (time_t)0) {
  452.         if(old_mtime != buf.st_mtime && printers) {
  453.             free_pr_list_item(printers);
  454.             printers = NULL;
  455.         }
  456.     }
  457.     old_mtime = buf.st_mtime;
  458. }
  459.  
  460.  
  461. /*
  462. ** build_pr_list
  463. **
  464. ** build a list of valid printers
  465. */
  466. #ifdef SVR4_STYLE_PR_LIST
  467.  
  468. int
  469. build_pr_list()
  470. {
  471. pr_list last = NULL;
  472. pr_list curr = NULL;
  473. char buff[256];
  474. char temp[256];
  475. FILE *p;
  476. char *cp;
  477. int saw_system;
  478.  
  479. /*
  480.  * In SVR4 the command to determine which printers are
  481.  * valid is lpstat -v. The output is something like this:
  482.  *
  483.  * device for lp: /dev/lp0
  484.  * system for pcdslw: hinode
  485.  * system for bletch: hinode (as printer hisname)
  486.  *
  487.  * On SunOS using the SysV compatibility package, the output
  488.  * is more like:
  489.  *
  490.  * device for lp is /dev/lp0
  491.  * device for pcdslw is the remote printer pcdslw on hinode
  492.  * device for bletch is the remote printer hisname on hinode
  493.  * device for billie is on  joy
  494.  * (if the /etc/printcap entry leaves out an "rp" field, using the "lp" default)
  495.  * No device or machine is    specified for billie
  496.  * (the last happens if a "whatever:tc=another" line appears in
  497.  * the /etc/printcap file to establish an alias).
  498.  *
  499.  * It is possible to create logic that will handle any of these
  500.  * possibilities, but note that such code is inherently sensitive
  501.  * to slight reformatting of message output (and breaks horribly
  502.  * under any kind of localization).
  503.  */
  504.  
  505.     p = popen("lpstat -v", "r");
  506.     if(p == NULL) {
  507.         printers = list_virtual_printers();
  508.         return(1);
  509.     }
  510.     
  511.     while(fgets(buff, 255, p) != NULL) {
  512.         cp = strtok(buff, delims);
  513.         if(!cp)
  514.             continue;
  515.         if (strcmp(cp, "No") == 0) {
  516.             static char *    badwords[] = {
  517.                 "device", "or", "machine", "is",
  518.                 "specified", "for", NULL
  519.                 };
  520.             int        joy;
  521.  
  522.             for (joy = 0; badwords[joy] != NULL; ++joy)
  523.                 if ((cp = strtok(NULL, delims)) == NULL ||
  524.                     strcmp(cp, badwords[joy]) != 0)
  525.                         break;
  526.             if (badwords[joy] != NULL)
  527.                 continue;
  528.             if ((cp = strtok(NULL, delims)) == NULL)
  529.                 continue;
  530.             if (strtok(NULL, delims) != NULL)
  531.                 continue;
  532.             curr = (struct pr_list_item *)
  533.                 grab(sizeof (struct pr_list_item));
  534.             curr->pn = my_strdup(cp);
  535.             curr->device = my_strdup("?");
  536.             curr->remhost = my_strdup("?");
  537.             curr->cm = my_strdup("(Incomplete configuration detected)");
  538.             curr->pr_next = NULL;
  539.             goto yo_lo_tengo;
  540.         }
  541.         if(!strcmp(cp, "device"))
  542.             saw_system = 0;
  543.         else if (!strcmp(cp, "system"))
  544.             saw_system = 1;
  545.         else
  546.             continue;
  547.         cp = strtok(NULL, delims);
  548.         if(!cp || strcmp(cp, "for"))
  549.             continue;
  550.         cp = strtok(NULL, delims);
  551.         if(!cp)
  552.             continue;
  553.         curr = (struct pr_list_item *)
  554.             grab(sizeof (struct pr_list_item));
  555.  
  556.         curr->pn = my_strdup(cp);
  557.         curr->device = NULL;
  558.         curr->remhost = NULL;
  559.         curr->cm = my_strdup("-");
  560.         curr->pr_next = NULL;
  561.         cp = strtok(NULL, delims);
  562.  
  563.         if(cp && !strcmp(cp, "is")) 
  564.             cp = strtok(NULL, delims);
  565.  
  566.         if(!cp) {
  567.             free_pr_list_item(curr);
  568.             continue;
  569.         }
  570.  
  571.         if(saw_system) {
  572.             /* "system" OR "system (as printer pname)" */ 
  573.             curr->remhost = my_strdup(cp);
  574.             
  575.             cp = strtok(NULL, delims);
  576.             if(!cp) {
  577.                 /* simple format */
  578.                 curr->device = my_strdup(curr->pn);
  579.                 sprintf(temp, "on %s", curr->remhost);
  580.             } else {
  581.                 /* "sys (as printer pname)" */
  582.                 if (strcmp(cp, "as")) {
  583.                     free_pr_list_item(curr);
  584.                     continue;
  585.                 }
  586.                 cp = strtok(NULL, delims);
  587.                 if (!cp || strcmp(cp, "printer")) {
  588.                     free_pr_list_item(curr);
  589.                     continue;
  590.                 }
  591.                 cp = strtok(NULL, delims);
  592.                 if(!cp) {
  593.                     free_pr_list_item(curr);
  594.                     continue;
  595.                 }
  596.                 curr->device = my_strdup(cp);
  597.                 sprintf(temp, "on %s as %s", curr->remhost, curr->device);
  598.             }
  599.             free(curr->cm); curr->cm = my_strdup(temp);
  600.             
  601.         }
  602.         else if(!strcmp(cp, "on")) {    /* deal with missing name */
  603.             cp = strtok(NULL, delims);
  604.             if(!cp) {
  605.                 free_pr_list_item(curr);
  606.                 continue;
  607.             }
  608.             curr->device = my_strdup("lp");
  609.             curr->remhost = my_strdup(cp);
  610.         }
  611.         else if(!strcmp(cp, "the")) {
  612.             /* start of "the remote printer foo on bar" */
  613.             cp = strtok(NULL, delims);
  614.             if(!cp || strcmp(cp, "remote")) {
  615.                 free_pr_list_item(curr);
  616.                 continue;
  617.             }
  618.             cp = strtok(NULL, delims);
  619.             if(!cp || strcmp(cp, "printer")) {
  620.                 free_pr_list_item(curr);
  621.                 continue;
  622.             }
  623.             cp = strtok(NULL, delims);
  624.             if(!cp) {
  625.                 free_pr_list_item(curr);
  626.                 continue;
  627.             }
  628.             curr->device = my_strdup(cp);
  629.             cp = strtok(NULL, delims);
  630.             if(!cp || strcmp(cp, "on")) {
  631.                 free_pr_list_item(curr);
  632.                 continue;
  633.             }
  634.             cp = strtok(NULL, delims);
  635.             if(!cp) {
  636.                 free_pr_list_item(curr);
  637.                 continue;
  638.             }
  639.             curr->remhost = my_strdup(cp);
  640.             sprintf(temp, "on %s as %s", curr->remhost, curr->device);
  641.             free(curr->cm); curr->cm = my_strdup(temp);
  642.         } else {
  643.             /* the local name */
  644.             curr->device = my_strdup(cp);
  645.             curr->remhost = my_strdup("");
  646.         }
  647.  
  648. yo_lo_tengo:
  649.         if(last == NULL)
  650.             printers = curr;
  651.         else
  652.             last->pr_next = curr;
  653.         last = curr;
  654.  
  655.     }
  656.     (void) pclose(p);
  657. /*
  658. ** Now add on the virtual printers, if any
  659. */
  660.     if(last == NULL)
  661.         printers = list_virtual_printers();
  662.     else
  663.         last->pr_next = list_virtual_printers();
  664.  
  665. #ifdef ACCEPT_BSD_PR_NAMES
  666. /*
  667. ** Build the alternative list with BSD names
  668. */
  669.     build_alt_pr_list();
  670. #endif ACCEPT_BSD_PR_NAMES
  671.  
  672.     return(1);
  673. }
  674. #endif SVR4_STYLE_PR_LIST
  675.  
  676.  
  677. #ifdef BSD_STYLE_PR_LIST
  678.  
  679. int
  680. build_pr_list()
  681. {
  682. pr_list last = NULL;
  683. pr_list curr = NULL;
  684. char buff[256];
  685. FILE *p;
  686. char *cp;
  687. int saw_system;
  688.  
  689. #ifdef BSD386
  690.     p = popen("/usr/sbin/lpc status", "r");
  691. #else
  692.     p = popen("/usr/etc/lpc status", "r");
  693. #endif BSD386
  694.     if(p == NULL) {
  695.         printers = list_virtual_printers();
  696.         return(1);
  697.     }
  698.     
  699.     while(fgets(buff, 255, p) != NULL) {
  700. /*
  701.  * This logic presumes that it's sufficient to find lines with
  702.  * a non-space first character. We should actually check for
  703.  * lines that begin "name:" - later
  704.  */
  705.         if(isspace(buff[0]))
  706.             continue;
  707.         cp = strtok(buff, delims);
  708.         if(!cp)
  709.             continue;
  710.         curr = (struct pr_list_item *)
  711.             grab(sizeof (struct pr_list_item));
  712.  
  713.         curr->pn = my_strdup(cp);
  714.         curr->device = NULL;
  715.         curr->remhost = NULL;
  716.         curr->cm = my_strdup("-");
  717.         curr->pr_next = NULL;
  718.         curr->device = my_strdup(cp);
  719.         curr->remhost = my_strdup("");
  720.         if(last == NULL)
  721.             printers = curr;
  722.         else
  723.             last->pr_next = curr;
  724.         last = curr;
  725.  
  726.     }
  727.     (void) pclose(p);
  728. /*
  729. ** Now add on the virtual printers, if any
  730. */
  731.     if(last == NULL)
  732.         printers = list_virtual_printers();
  733.     else
  734.         last->pr_next = list_virtual_printers();
  735.  
  736.     return(1);
  737. }
  738. #endif BSD_STYLE_PR_LIST
  739.  
  740.  
  741.  
  742. #ifdef ACCEPT_BSD_PR_NAMES
  743. /*
  744. ** build_alt_pr_list
  745. **
  746. ** build a list of alternative valid printers (BSD names)
  747. ** - but only if the standard list is SVR4 style
  748. */
  749. #ifdef SVR4_STYLE_PR_LIST
  750.  
  751. int
  752. build_alt_pr_list()
  753. {
  754. pr_list last = NULL;
  755. pr_list curr = NULL;
  756. char buff[256];
  757. FILE *p;
  758. char *cp;
  759. int saw_system;
  760.  
  761.     p = popen("/usr/etc/lpc status", "r");
  762.     if(p == NULL)
  763.         return(1);    /* Don't use alt list    */
  764.     
  765.     while(fgets(buff, 255, p) != NULL) {
  766. /*
  767.  * This logic presumes that it's sufficient to find lines with
  768.  * a non-space first character. We should actually check for
  769.  * lines that begin "name:" - later
  770.  */
  771.         if(isspace(buff[0]))
  772.             continue;
  773.         cp = strtok(buff, delims);
  774.         if(!cp)
  775.             continue;
  776.         curr = (struct pr_list_item *)
  777.             grab(sizeof (struct pr_list_item));
  778.  
  779.         curr->pn = my_strdup(cp);
  780.         curr->device = NULL;
  781.         curr->remhost = NULL;
  782.         curr->cm = my_strdup("(alternative BSD-style name)");
  783.         curr->pr_next = NULL;
  784.         curr->device = my_strdup(cp);
  785.         curr->remhost = my_strdup("");
  786.         if(last == NULL)
  787.             alt_printers = curr;
  788.         else
  789.             last->pr_next = curr;
  790.         last = curr;
  791.  
  792.     }
  793.     (void) pclose(p);
  794.     return(1);
  795. }
  796. #endif SVR4_STYLE_PR_LIST
  797. #endif ACCEPT_BSD_PR_NAMES
  798.  
  799.  
  800. /*
  801. ** free_pr_list_item
  802. **
  803. ** free a list of printers recursively, item by item
  804. */
  805. void
  806. free_pr_list_item(curr)
  807. pr_list curr;
  808. {
  809.     if(curr->pn)
  810.         free(curr->pn);
  811.     if(curr->device)
  812.         free(curr->device);
  813.     if(curr->remhost)
  814.         free(curr->remhost);
  815.     if(curr->cm)
  816.         free(curr->cm);
  817.     if(curr->pr_next)
  818.         free_pr_list_item(curr->pr_next); /* recurse */
  819.     free(curr);
  820. }
  821.  
  822. /*
  823. ** build_pr_queue
  824. **
  825. ** generate a printer queue listing
  826. */
  827.  
  828. #ifdef SVR4_STYLE_QUEUE
  829.  
  830. /*
  831. ** Print queue handling.
  832. **
  833. ** Note that the first thing we do is to discard any
  834. ** existing queue.
  835. */
  836.  
  837. pirstat
  838. build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
  839. printername     pn;
  840. username        user;
  841. int            just_mine;
  842. int            *p_qlen;
  843. int            *p_qshown;
  844. {
  845. pr_queue last = NULL;
  846. pr_queue curr = NULL;
  847. char buff[256];
  848. FILE *p;
  849. char *owner;
  850. char *job;
  851. char *totsize;
  852.  
  853.     if(queue) {
  854.         free_pr_queue_item(queue);
  855.         queue = NULL;
  856.     }
  857.     *p_qlen = 0;
  858.     *p_qshown = 0;
  859.  
  860.     pn = map_printer_name(pn);
  861.     if(pn == NULL || !valid_pr(pn) || suspicious(pn))
  862.         return(PI_RES_NO_SUCH_PRINTER);
  863.  
  864.  
  865. /*
  866. ** In SVR4 the command to list the print jobs for printer
  867. ** lp is "lpstat lp" (or, equivalently, "lpstat -p lp").
  868. ** The output looks like this:
  869. ** 
  870. ** lp-2                    root               939   Jul 10 21:56
  871. ** lp-5                    geoff               15   Jul 12 23:23
  872. ** lp-6                    geoff               15   Jul 12 23:23
  873. ** 
  874. ** If the first job is actually printing the first line
  875. ** is modified, as follows:
  876. **
  877. ** lp-2                    root               939   Jul 10 21:56 on lp
  878. ** 
  879. ** I don't yet have any info on what it looks like if the printer
  880. ** is remote and we're spooling over the net. However for
  881. ** the purposes of rpc.pcnfsd we can simply say that field 1 is the
  882. ** job ID, field 2 is the submitter, and field 3 is the size.
  883. ** We can check for the presence of the string " on " in the
  884. ** first record to determine if we should count it as rank 0 or rank 1,
  885. ** but it won't hurt if we get it wrong.
  886. **/
  887.     sprintf(buff, "/usr/bin/lpstat %s", pn);
  888.     p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
  889.     if(p == NULL) {
  890.         msg_out("rpc.pcnfsd: unable to popen() lpstat queue query");
  891.         return(PI_RES_FAIL);
  892.     }
  893.     
  894.     while(fgets(buff, 255, p) != NULL) {
  895.         job = strtok(buff, delims);
  896.         if(!job)
  897.             continue;
  898.  
  899.         owner = strtok(NULL, delims);
  900.         if(!owner)
  901.             continue;
  902.  
  903.         totsize = strtok(NULL, delims);
  904.         if(!totsize)
  905.             continue;
  906.  
  907.         *p_qlen += 1;
  908.  
  909.         if(*p_qshown > QMAX)
  910.             continue;
  911.  
  912.         if(just_mine && mystrcasecmp(owner, user))
  913.             continue;
  914.  
  915.         *p_qshown += 1;
  916.  
  917.         curr = (struct pr_queue_item *)
  918.             grab(sizeof (struct pr_queue_item));
  919.  
  920.         curr->position = *p_qlen;
  921.         curr->id = my_strdup(job);
  922.         curr->size = my_strdup(totsize);
  923.         curr->status = my_strdup("");
  924.         curr->system = my_strdup("");
  925.         curr->user = my_strdup(owner);
  926.         curr->file = my_strdup("");
  927.         curr->cm = my_strdup("-");
  928.         curr->pr_next = NULL;
  929.  
  930.         if(last == NULL)
  931.             queue = curr;
  932.         else
  933.             last->pr_next = curr;
  934.         last = curr;
  935.  
  936.     }
  937.     (void) su_pclose(p);
  938.     return(PI_RES_OK);
  939. }
  940.  
  941. #endif SVR4_STYLE_QUEUE
  942.  
  943. #ifdef BSD_STYLE_QUEUE
  944. /*
  945.  * BSD style queue listing
  946.  */
  947.  
  948. pirstat
  949. build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
  950. printername     pn;
  951. username        user;
  952. int            just_mine;
  953. int            *p_qlen;
  954. int            *p_qshown;
  955. {
  956. pr_queue last = NULL;
  957. pr_queue curr = NULL;
  958. char buff[256];
  959. FILE *p;
  960. char *cp;
  961. int i;
  962. char *rank;
  963. char *owner;
  964. char *job;
  965. char *files;
  966. char *totsize;
  967.  
  968.     if(queue) {
  969.         free_pr_queue_item(queue);
  970.         queue = NULL;
  971.     }
  972.     *p_qlen = 0;
  973.     *p_qshown = 0;
  974.     pn = map_printer_name(pn);
  975.     if(pn == NULL || suspicious(pn) || !valid_pr(pn))
  976.         return(PI_RES_NO_SUCH_PRINTER);
  977.  
  978. #ifdef BSD386
  979.     sprintf(buff, "/usr/bin/lpq -P%s", pn);
  980. #else
  981.         sprintf(buff, "/usr/ucb/lpq -P%s", pn);
  982. #endif BSD386
  983.  
  984.     p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
  985.     if(p == NULL) {
  986.         msg_out("rpc.pcnfsd: unable to popen() lpq");
  987.         return(PI_RES_FAIL);
  988.     }
  989.     
  990.     while(fgets(buff, 255, p) != NULL) {
  991.         i = strlen(buff) - 1;
  992.         buff[i] = '\0';        /* zap trailing NL */
  993.         if(i < SIZECOL)
  994.             continue;
  995.         if(!mystrncasecmp(buff, "rank", 4))
  996.             continue;
  997.  
  998.         if(!mystrncasecmp(buff, "warning", 7))
  999.             continue;
  1000.  
  1001.         totsize = &buff[SIZECOL-1];
  1002.         files = &buff[FILECOL-1];
  1003.         cp = totsize;
  1004.         cp--;
  1005.         while(cp > files && isspace(*cp))
  1006.             *cp-- = '\0';
  1007.  
  1008.         buff[FILECOL-2] = '\0';
  1009.  
  1010.         cp = strtok(buff, delims);
  1011.         if(!cp)
  1012.             continue;
  1013.         rank = cp;
  1014.  
  1015.         cp = strtok(NULL, delims);
  1016.         if(!cp)
  1017.             continue;
  1018.         owner = cp;
  1019.  
  1020.         cp = strtok(NULL, delims);
  1021.         if(!cp)
  1022.             continue;
  1023.         job = cp;
  1024.  
  1025.         *p_qlen += 1;
  1026.  
  1027.         if(*p_qshown > QMAX)
  1028.             continue;
  1029.  
  1030.         if(just_mine && mystrcasecmp(owner, user))
  1031.             continue;
  1032.  
  1033.         *p_qshown += 1;
  1034.  
  1035.         curr = (struct pr_queue_item *)
  1036.             grab(sizeof (struct pr_queue_item));
  1037.  
  1038.         curr->position = atoi(rank); /* active -> 0 */
  1039.         curr->id = my_strdup(job);
  1040.         curr->size = my_strdup(totsize);
  1041.         curr->status = my_strdup(rank);
  1042.         curr->system = my_strdup("");
  1043.         curr->user = my_strdup(owner);
  1044.         curr->file = my_strdup(files);
  1045.         curr->cm = my_strdup("-");
  1046.         curr->pr_next = NULL;
  1047.  
  1048.         if(last == NULL)
  1049.             queue = curr;
  1050.         else
  1051.             last->pr_next = curr;
  1052.         last = curr;
  1053.  
  1054.     }
  1055.     (void) su_pclose(p);
  1056.     return(PI_RES_OK);
  1057. }
  1058. #endif BSD_STYLE_QUEUE
  1059.  
  1060.  
  1061. /*
  1062. ** free_pr_queue_item
  1063. **
  1064. ** recursively free a pr_queue, item by item
  1065. */
  1066. void
  1067. free_pr_queue_item(curr)
  1068. pr_queue curr;
  1069. {
  1070.     if(curr->id)
  1071.         free(curr->id);
  1072.     if(curr->size)
  1073.         free(curr->size);
  1074.     if(curr->status)
  1075.         free(curr->status);
  1076.     if(curr->system)
  1077.         free(curr->system);
  1078.     if(curr->user)
  1079.         free(curr->user);
  1080.     if(curr->file)
  1081.         free(curr->file);
  1082.     if(curr->cm)
  1083.         free(curr->cm);
  1084.     if(curr->pr_next)
  1085.         free_pr_queue_item(curr->pr_next); /* recurse */
  1086.     free(curr);
  1087. }
  1088.  
  1089.  
  1090.  
  1091.  
  1092. /*
  1093. ** get_pr_status
  1094. **
  1095. ** generate printer status report
  1096. */
  1097. #ifdef SVR4_STYLE_STATUS
  1098.  
  1099. pirstat
  1100. get_pr_status(pn, avail, printing, qlen, needs_operator, status)
  1101. printername   pn;
  1102. bool_t       *avail;
  1103. bool_t       *printing;
  1104. int          *qlen;
  1105. bool_t       *needs_operator;
  1106. char         *status;
  1107. {
  1108. char buff[256];
  1109. char cmd[64];
  1110. FILE *p;
  1111. int n;
  1112. pirstat stat = PI_RES_NO_SUCH_PRINTER;
  1113.  
  1114. /*
  1115. ** New - SVR4 printer status handling.
  1116. **
  1117. ** The command we'll use for checking the status of printer "lp"
  1118. ** is "lpstat -a lp -p lp". Here are some sample outputs:
  1119. **
  1120. ** 
  1121. ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
  1122. ** printer lp disabled since Thu Feb 21 22:52:36 EST 1991. available.
  1123. **     new printer
  1124. ** ---
  1125. ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
  1126. **     unknown reason
  1127. ** printer pcdslw disabled since Fri Jul 12 22:15:37 EDT 1991. available.
  1128. **     new printer
  1129. ** ---
  1130. ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
  1131. ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
  1132. ** ---
  1133. ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
  1134. ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
  1135. ** ---
  1136. ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
  1137. ** printer lp disabled since Sat Jul 13 12:05:20 EDT 1991. available.
  1138. **     unknown reason
  1139. ** ---
  1140. ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
  1141. **     unknown reason
  1142. ** printer pcdslw is idle. enabled since Sat Jul 13 12:05:28 EDT 1991. available.
  1143. **
  1144. ** Note that these are actual outputs. The format (which is totally
  1145. ** different from the lpstat in SunOS) seems to break down as
  1146. ** follows:
  1147. ** (1) The first line has the form "printername [not] accepting requests,,,"
  1148. **    This is trivial to decode.
  1149. ** (2) The second line has several forms, all beginning "printer printername":
  1150. ** (2.1) "... disabled"
  1151. ** (2.2) "... is idle"
  1152. ** (2.3) "... now printing jobid"
  1153. ** The "available" comment seems to be meaningless. The next line
  1154. ** is the "reason" code which the operator can supply when issuing
  1155. ** a "disable" or "reject" command.
  1156. ** Note that there is no way to check the number of entries in the
  1157. ** queue except to ask for the queue and count them.
  1158. */
  1159.     /* assume the worst */
  1160.     *avail = FALSE;
  1161.     *printing = FALSE;
  1162.     *needs_operator = FALSE;
  1163.     *qlen = 0;
  1164.     *status = '\0';
  1165.  
  1166.     pn = map_printer_name(pn);
  1167.     if(pn == NULL || !valid_pr(pn) || suspicious(pn))
  1168.         return(PI_RES_NO_SUCH_PRINTER);
  1169.     n = strlen(pn);
  1170.  
  1171.     sprintf(cmd, "/usr/bin/lpstat -a %s -p %s", pn, pn);
  1172.  
  1173.     p = popen(cmd, "r");
  1174.     if(p == NULL) {
  1175.         msg_out("rpc.pcnfsd: unable to popen() lp status");
  1176.         return(PI_RES_FAIL);
  1177.     }
  1178.     
  1179.     stat = PI_RES_OK;
  1180.  
  1181.     while(fgets(buff, 255, p) != NULL) {
  1182.         if(!strncmp(buff, pn, n)) {
  1183.             if(!strstr(buff, "not accepting"))
  1184.             *avail = TRUE;
  1185.             continue;
  1186.         }
  1187.         if(!strncmp(buff, "printer ", 8)) {
  1188.             if(!strstr(buff, "disabled"))
  1189.                 *printing = TRUE;
  1190.             if(strstr(buff, "printing"))
  1191.                 strcpy(status, "printing");
  1192.             else if (strstr(buff, "idle"))
  1193.                 strcpy(status, "idle");
  1194.             continue;
  1195.         }
  1196.         if(!strncmp(buff, "UX:", 3)) {
  1197.             stat = PI_RES_NO_SUCH_PRINTER;
  1198.         }
  1199.     }
  1200.     (void) pclose(p);
  1201.     return(stat);
  1202. }
  1203. #endif SVR4_STYLE_STATUS
  1204.  
  1205. #ifdef BSD_STYLE_STATUS
  1206.  
  1207. pirstat
  1208. get_pr_status(pn, avail, printing, qlen, needs_operator, status)
  1209. printername   pn;
  1210. bool_t       *avail;
  1211. bool_t       *printing;
  1212. int          *qlen;
  1213. bool_t       *needs_operator;
  1214. char         *status;
  1215. {
  1216. char cmd[128];
  1217. char buff[256];
  1218. char buff2[256];
  1219. char pname[64];
  1220. FILE *p;
  1221. char *cp;
  1222. char *cp1;
  1223. char *cp2;
  1224. int n;
  1225. pirstat stat = PI_RES_NO_SUCH_PRINTER;
  1226.  
  1227.     /* assume the worst */
  1228.     *avail = FALSE;
  1229.     *printing = FALSE;
  1230.     *needs_operator = FALSE;
  1231.     *qlen = 0;
  1232.     *status = '\0';
  1233.  
  1234.     pn = map_printer_name(pn);
  1235.     if(pn == NULL || suspicious(pn) || !valid_pr(pn))
  1236.         return(PI_RES_NO_SUCH_PRINTER);
  1237.  
  1238.     sprintf(pname, "%s:", pn);
  1239.     n = strlen(pname);
  1240.  
  1241. #ifdef BSD386
  1242.     sprintf(cmd, "/usr/sbin/lpc status %s", pn);
  1243. #else
  1244.     sprintf(cmd, "/usr/etc/lpc status %s", pn);
  1245. #endif BSD386
  1246.     p = popen(cmd, "r");
  1247.     if(p == NULL) {
  1248.         msg_out("rpc.pcnfsd: unable to popen() lpc status");
  1249.         return(PI_RES_FAIL);
  1250.     }
  1251.     
  1252.     while(fgets(buff, 255, p) != NULL) {
  1253.         if(strncmp(buff, pname, n))
  1254.             continue;
  1255. /*
  1256. ** We have a match. The only failure now is PI_RES_FAIL if
  1257. ** lpstat output cannot be decoded
  1258. */
  1259.         stat = PI_RES_FAIL;
  1260. /*
  1261. ** The next four lines are usually if the form
  1262. **
  1263. **     queuing is [enabled|disabled]
  1264. **     printing is [enabled|disabled]
  1265. **     [no entries | N entr[y|ies] in spool area]
  1266. **     <status message, may include the word "attention">
  1267. */
  1268.         while(fgets(buff, 255, p) != NULL && isspace(buff[0])) {
  1269.             cp = buff;
  1270.             while(isspace(*cp))
  1271.                 cp++;
  1272.             if(*cp == '\0')
  1273.                 break;
  1274.             cp1 = cp;
  1275.             cp2 = buff2;
  1276.             while(*cp1 && *cp1 != '\n') {
  1277.                 *cp2++ = 
  1278.                     (isupper(*cp1) ? tolower(*cp1) : *cp1);
  1279.                 cp1++;
  1280.             }
  1281.             *cp1 = '\0';
  1282.             *cp2 = '\0';
  1283. /*
  1284. ** Now buff2 has a lower-cased copy and cp points at the original;
  1285. ** both are null terminated without any newline
  1286. */            
  1287.             if(!strncmp(buff2, "queuing", 7)) {
  1288.                 *avail = (strstr(buff2, "enabled") != NULL);
  1289.                 continue;
  1290.             }
  1291.             if(!strncmp(buff2, "printing", 8)) {
  1292.                 *printing = (strstr(buff2, "enabled") != NULL);
  1293.                 continue;
  1294.             }
  1295.             if(isdigit(buff2[0]) && (strstr(buff2, "entr") !=NULL)) {
  1296.  
  1297.                 *qlen = atoi(buff2);
  1298.                 continue;
  1299.             }
  1300.             if(strstr(buff2, "attention") != NULL ||
  1301.                strstr(buff2, "error") != NULL)
  1302.                 *needs_operator = TRUE;
  1303.             if(*needs_operator || strstr(buff2, "waiting") != NULL)
  1304.                 strcpy(status, cp);
  1305.         }
  1306.         stat = PI_RES_OK;
  1307.         break;
  1308.     }
  1309.     (void) pclose(p);
  1310.     return(stat);
  1311. }
  1312. #endif BSD_STYLE_STATUS
  1313.  
  1314. /*
  1315. ** pr_cancel
  1316. **
  1317. ** cancel job id on printer pr on behalf of user
  1318. */
  1319.  
  1320. #ifdef SVR4_STYLE_CANCEL
  1321.  
  1322. pcrstat pr_cancel(pr, user, id)
  1323. char *pr;
  1324. char *user;
  1325. char *id;
  1326. {
  1327. char            cmdbuf[256];
  1328. char            resbuf[256];
  1329. FILE *fd;
  1330. pcrstat stat = PC_RES_NO_SUCH_JOB;
  1331.  
  1332.     pr = map_printer_name(pr);
  1333.     if(pr == NULL || suspicious(pr) || !valid_pr(pr))
  1334.         return(PC_RES_NO_SUCH_PRINTER);
  1335.     if(suspicious(id))
  1336.         return(PC_RES_NO_SUCH_JOB);
  1337.  
  1338.     sprintf(cmdbuf, "/usr/bin/cancel %s", id);
  1339.     if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
  1340.         msg_out("rpc.pcnfsd: su_popen failed");
  1341.         return(PC_RES_FAIL);
  1342.     }
  1343. /*
  1344. ** For SVR4 we have to be prepared for the following kinds of output:
  1345. ** 
  1346. ** # cancel lp-6
  1347. ** request "lp-6" cancelled
  1348. ** # cancel lp-33
  1349. ** UX:cancel: WARNING: Request "lp-33" doesn't exist.
  1350. ** # cancel foo-88
  1351. ** UX:cancel: WARNING: Request "foo-88" doesn't exist.
  1352. ** # cancel foo
  1353. ** UX:cancel: WARNING: "foo" is not a request id or a printer.
  1354. **             TO FIX: Cancel requests by id or by
  1355. **                     name of printer where printing.
  1356. ** # su geoff
  1357. ** $ cancel lp-2
  1358. ** UX:cancel: WARNING: Can't cancel request "lp-2".
  1359. **             TO FIX: You are not allowed to cancel
  1360. **                     another's request.
  1361. **
  1362. ** There are probably other variations for remote printers.
  1363. ** Basically, if the reply begins with the string
  1364. **          "UX:cancel: WARNING: "
  1365. ** we can strip this off and look for one of the following
  1366. ** (1) 'R' - should be part of "Request "xxxx" doesn't exist."
  1367. ** (2) '"' - should be start of ""foo" is not a request id or..."
  1368. ** (3) 'C' - should be start of "Can't cancel request..."
  1369. **
  1370. ** The fly in the ointment: all of this can change if these
  1371. ** messages are localized..... :-(
  1372. */
  1373.     if(fgets(resbuf, 255, fd) == NULL) 
  1374.         stat = PC_RES_FAIL;
  1375.     else if(!strstr(resbuf, "UX:"))
  1376.         stat = PC_RES_OK;
  1377.     else if(strstr(resbuf, "doesn't exist"))
  1378.         stat = PC_RES_NO_SUCH_JOB;
  1379.     else if(strstr(resbuf, "not a request id"))
  1380.         stat = PC_RES_NO_SUCH_JOB;
  1381.     else if(strstr(resbuf, "Can't cancel request"))
  1382.         stat = PC_RES_NOT_OWNER;
  1383.     else    stat = PC_RES_FAIL;
  1384.  
  1385.     if(su_pclose(fd) == 255)
  1386.         msg_out("rpc.pcnfsd: su_pclose alert");
  1387.     return(stat);
  1388. }
  1389.  
  1390. #endif SVR4_STYLE_CANCEL
  1391.  
  1392. #ifdef BSD_STYLE_CANCEL
  1393.  
  1394. pcrstat pr_cancel(pr, user, id)
  1395. char *pr;
  1396. char *user;
  1397. char *id;
  1398. {
  1399. char            cmdbuf[256];
  1400. char            resbuf[256];
  1401. FILE *fd;
  1402. int i;
  1403. pcrstat stat = PC_RES_NO_SUCH_JOB;
  1404.  
  1405.     pr = map_printer_name(pr);
  1406.     if(pr == NULL || suspicious(pr) || !valid_pr(pr))
  1407.         return(PC_RES_NO_SUCH_PRINTER);
  1408.     if(suspicious(id))
  1409.         return(PC_RES_NO_SUCH_JOB);
  1410.  
  1411. #ifdef BSD386
  1412.         sprintf(cmdbuf, "/usr/bin/lprm -P%s %s", pr, id);
  1413. #else
  1414.         sprintf(cmdbuf, "/usr/ucb/lprm -P%s %s", pr, id);
  1415. #endif BSD386
  1416.         if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
  1417.             msg_out("rpc.pcnfsd: su_popen failed");
  1418.             return(PC_RES_FAIL);
  1419.         }
  1420.         while(fgets(resbuf, 255, fd) != NULL) {
  1421.             i = strlen(resbuf);
  1422.             if(i)
  1423.                 resbuf[i-1] = '\0'; /* trim NL */
  1424.             if(strstr(resbuf, "dequeued") != NULL)
  1425.                 stat = PC_RES_OK;
  1426.             if(strstr(resbuf, "unknown printer") != NULL)
  1427.                 stat = PC_RES_NO_SUCH_PRINTER;
  1428.             if(strstr(resbuf, "Permission denied") != NULL)
  1429.                 stat = PC_RES_NOT_OWNER;
  1430.         }
  1431.         if(su_pclose(fd) == 255)
  1432.             msg_out("rpc.pcnfsd: su_pclose alert");
  1433.         return(stat);
  1434. }
  1435. #endif BSD_STYLE_CANCEL
  1436.  
  1437. /*
  1438. ** New subsystem here. We allow the administrator to define
  1439. ** up to NPRINTERDEFS aliases for printer names. This is done
  1440. ** using the "/etc/pcnfsd.conf" file, which is read at startup.
  1441. ** There are three entry points to this subsystem
  1442. **
  1443. ** void add_printer_alias(char *printer, char *alias_for, char *command)
  1444. **
  1445. ** This is invoked from "config_from_file()" for each
  1446. ** "printer" line. "printer" is the name of a printer; note that
  1447. ** it is possible to redefine an existing printer. "alias_for"
  1448. ** is the name of the underlying printer, used for queue listing
  1449. ** and other control functions. If it is "-", there is no
  1450. ** underlying printer, or the administrative functions are
  1451. ** not applicable to this printer. "command"
  1452. ** is the command which should be run (via "su_popen()") if a
  1453. ** job is printed on this printer. The following tokens may be
  1454. ** embedded in the command, and are substituted as follows:
  1455. **
  1456. ** $FILE    -    path to the file containing the print data
  1457. ** $USER    -    login of user
  1458. ** $HOST    -    hostname from which job originated
  1459. **
  1460. ** Tokens may occur multiple times. If The command includes no
  1461. ** $FILE token, the string " $FILE" is silently appended.
  1462. **
  1463. ** pr_list list_virtual_printers()
  1464. **
  1465. ** This is invoked from build_pr_list to generate a list of aliased
  1466. ** printers, so that the client that asks for a list of valid printers
  1467. ** will see these ones.
  1468. **
  1469. ** char *map_printer_name(char *printer)
  1470. **
  1471. ** If "printer" identifies an aliased printer, this function returns
  1472. ** the "alias_for" name, or NULL if the "alias_for" was given as "-".
  1473. ** Otherwise it returns its argument.
  1474. **
  1475. ** char *expand_alias(char *printer, char *file, char *user, char *host)
  1476. **
  1477. ** If "printer" is an aliased printer, this function returns a
  1478. ** pointer to a static string in which the corresponding command
  1479. ** has been expanded. Otherwise ot returns NULL.
  1480. */
  1481. #define NPRINTERDEFS    128
  1482. int num_aliases = 0;
  1483. struct {
  1484.     char *a_printer;
  1485.     char *a_alias_for;
  1486.     char *a_command;
  1487. } alias [NPRINTERDEFS];
  1488.  
  1489.  
  1490. #ifdef SVR4_STYLE_PRINT
  1491. char default_cmd[] = "lp $FILE";
  1492. #endif SVR4_STYLE_PRINT
  1493. #ifdef BSD_STYLE_PRINT
  1494. #ifdef BSD386
  1495. char default_cmd[] = "/usr/bin/lpr $FILE";
  1496. #else
  1497. char default_cmd[] = "/usr/ucb/lpr $FILE";
  1498. #endif BSD386
  1499. #endif BSD_STYLE_PRINT
  1500.  
  1501. void
  1502. add_printer_alias(printer, alias_for, command)
  1503. char *printer;
  1504. char *alias_for;
  1505. char *command;
  1506. {
  1507. /*
  1508.  * Add a little bullet-proofing here
  1509.  */
  1510.     if(alias_for == NULL || strlen(alias_for) == 0)
  1511.         alias_for = "lp";
  1512.     if(command == NULL || strlen(command) == 0)
  1513.         command = default_cmd;    /* see above */
  1514.     if(num_aliases < NPRINTERDEFS) {
  1515.         alias[num_aliases].a_printer = my_strdup(printer);
  1516.         alias[num_aliases].a_alias_for =
  1517.             (strcmp(alias_for,  "-") ? my_strdup(alias_for) : NULL);
  1518.         if(strstr(command, "$FILE"))
  1519.             alias[num_aliases].a_command = my_strdup(command);
  1520.         else {
  1521.             alias[num_aliases].a_command =
  1522.                 (char *)grab(strlen(command) + 8);
  1523.             strcpy(alias[num_aliases].a_command, command);
  1524.             strcat(alias[num_aliases].a_command, " $FILE");
  1525.         }
  1526.         num_aliases++;
  1527.     }
  1528. }
  1529.  
  1530.  
  1531. /*
  1532. ** list_virtual_printers
  1533. **
  1534. ** build a pr_list of all virtual printers (if any)
  1535. */
  1536. pr_list list_virtual_printers()
  1537. {
  1538. pr_list first = NULL;
  1539. pr_list last = NULL;
  1540. pr_list curr = NULL;
  1541. int i;
  1542.  
  1543.  
  1544.  
  1545.     if(num_aliases == 0)
  1546.         return(NULL);
  1547.  
  1548.     for (i = 0; i < num_aliases; i++) {
  1549.         curr = (struct pr_list_item *)
  1550.             grab(sizeof (struct pr_list_item));
  1551.  
  1552.         curr->pn = my_strdup(alias[i].a_printer);
  1553.         if(alias[i].a_alias_for == NULL)
  1554.             curr->device = my_strdup("");
  1555.         else
  1556.             curr->device = my_strdup(alias[i].a_alias_for);
  1557.         curr->remhost = my_strdup("");
  1558.         curr->cm = my_strdup("(alias)");
  1559.         curr->pr_next = NULL;
  1560.         if(last == NULL)
  1561.             first = curr;
  1562.         else
  1563.             last->pr_next = curr;
  1564.         last = curr;
  1565.  
  1566.     }
  1567.     return(first);
  1568. }
  1569.  
  1570.  
  1571.  
  1572. /*
  1573. ** map_printer_name
  1574. **
  1575. ** if a printer name is actually an alias, return the name of
  1576. ** the printer for which it is an alias; otherwise return the name
  1577. */
  1578. char *
  1579. map_printer_name(printer)
  1580. char *printer;
  1581. {
  1582. int i;
  1583.     for (i = 0; i < num_aliases; i++){
  1584.         if(!strcmp(printer, alias[i].a_printer))
  1585.             return(alias[i].a_alias_for);
  1586.     }
  1587.     return(printer);
  1588. }
  1589.  
  1590.  
  1591. /*
  1592. ** substitute
  1593. **
  1594. ** replace a token in a string as often as it occurs
  1595. */
  1596. static void
  1597. substitute(string, token, data)
  1598. char *string;
  1599. char *token;
  1600. char *data;
  1601. {
  1602. char temp[512];
  1603. char *c;
  1604.  
  1605.     while(c = strstr(string, token)) {
  1606.         *c = '\0';
  1607.         strcpy(temp, string);
  1608.         strcat(temp, data);
  1609.         c += strlen(token);
  1610.         strcat(temp, c);
  1611.         strcpy(string, temp);
  1612.     }
  1613. }
  1614.  
  1615.  
  1616. /*
  1617. ** expand_alias
  1618. **
  1619. ** expand an aliased printer command by substituting file/user/host
  1620. */
  1621. char *
  1622. expand_alias(printer, file, user, host)
  1623. char *printer;
  1624. char *file;
  1625. char *user;
  1626. char *host;
  1627. {
  1628. static char expansion[512];
  1629. int i;
  1630.     for (i = 0; i < num_aliases; i++){
  1631.         if(!strcmp(printer, alias[i].a_printer)) {
  1632.             strcpy(expansion, alias[i].a_command);
  1633.             substitute(expansion, "$FILE", file);
  1634.             substitute(expansion, "$USER", user);
  1635.             substitute(expansion, "$HOST", host);
  1636.             return(expansion);
  1637.         }
  1638.     }
  1639.     return(NULL);
  1640. }
  1641.