xref: /netbsd/usr.sbin/rpc.pcnfsd/pcnfsd_print.c (revision 0466bbb6)
1*0466bbb6Slukem /*	$NetBSD: pcnfsd_print.c,v 1.9 2009/04/18 13:02:36 lukem Exp $	*/
2457d5a17Sgwr 
382b75dfdSjtc /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_print.c 1.7 92/01/24 19:58:58 SMI */
482b75dfdSjtc /*
582b75dfdSjtc **=====================================================================
682b75dfdSjtc ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
782b75dfdSjtc **	@(#)pcnfsd_print.c	1.7	1/24/92
882b75dfdSjtc **=====================================================================
982b75dfdSjtc */
1082b75dfdSjtc /*
1182b75dfdSjtc **=====================================================================
1282b75dfdSjtc **             I N C L U D E   F I L E   S E C T I O N                *
1382b75dfdSjtc **                                                                    *
1482b75dfdSjtc ** If your port requires different include files, add a suitable      *
1582b75dfdSjtc ** #define in the customization section, and make the inclusion or    *
1682b75dfdSjtc ** exclusion of the files conditional on this.                        *
1782b75dfdSjtc **=====================================================================
1882b75dfdSjtc */
19736ba086Slukem 
2082b75dfdSjtc #include <sys/file.h>
2182b75dfdSjtc #include <sys/ioctl.h>
22736ba086Slukem #include <sys/stat.h>
23736ba086Slukem 
24736ba086Slukem #include <ctype.h>
2582b75dfdSjtc #include <errno.h>
26736ba086Slukem #include <netdb.h>
27736ba086Slukem #include <pwd.h>
28736ba086Slukem #include <signal.h>
29736ba086Slukem #include <stdio.h>
30736ba086Slukem #include <stdlib.h>
3182b75dfdSjtc #include <string.h>
32736ba086Slukem #include <unistd.h>
3382b75dfdSjtc 
3482b75dfdSjtc #ifndef SYSV
3582b75dfdSjtc #include <sys/wait.h>
3682b75dfdSjtc #endif
3782b75dfdSjtc 
3882b75dfdSjtc #ifdef ISC_2_0
3982b75dfdSjtc #include <sys/fcntl.h>
4082b75dfdSjtc #endif
4182b75dfdSjtc 
4282b75dfdSjtc #ifdef SHADOW_SUPPORT
4382b75dfdSjtc #include <shadow.h>
4482b75dfdSjtc #endif
4582b75dfdSjtc 
466f885de1Sgwr #include "paths.h"
476f885de1Sgwr 
48736ba086Slukem #include "common.h"
49736ba086Slukem #include "pcnfsd.h"
50736ba086Slukem #include "extern.h"
51736ba086Slukem 
5282b75dfdSjtc /*
5382b75dfdSjtc **---------------------------------------------------------------------
5482b75dfdSjtc ** Other #define's
5582b75dfdSjtc **---------------------------------------------------------------------
5682b75dfdSjtc */
5782b75dfdSjtc #ifndef MAXPATHLEN
5882b75dfdSjtc #define MAXPATHLEN 1024
5982b75dfdSjtc #endif
6082b75dfdSjtc 
6182b75dfdSjtc /*
62b1c7ac0eSwiz ** The following definitions give the maximum time allowed for
6382b75dfdSjtc ** an external command to run (in seconds)
6482b75dfdSjtc */
6582b75dfdSjtc #define MAXTIME_FOR_PRINT	10
6682b75dfdSjtc #define MAXTIME_FOR_QUEUE	10
6782b75dfdSjtc #define MAXTIME_FOR_CANCEL	10
6882b75dfdSjtc #define MAXTIME_FOR_STATUS	10
6982b75dfdSjtc 
7082b75dfdSjtc #define QMAX 50
7182b75dfdSjtc 
7282b75dfdSjtc /*
7382b75dfdSjtc ** The following is derived from ucb/lpd/displayq.c
7482b75dfdSjtc */
7582b75dfdSjtc #define SIZECOL 62
7682b75dfdSjtc #define FILECOL 24
7782b75dfdSjtc 
78736ba086Slukem char   *expand_alias __P((char *, char *, char *, char *));
79736ba086Slukem pr_list	list_virtual_printers __P((void));
80736ba086Slukem char   *map_printer_name __P((char *));
81*0466bbb6Slukem void	substitute __P((char *, const char *, const char *));
82736ba086Slukem int	suspicious __P((char *));
83736ba086Slukem int	valid_pr __P((char *));
8482b75dfdSjtc 
8582b75dfdSjtc /*
8682b75dfdSjtc **---------------------------------------------------------------------
8782b75dfdSjtc **                       Misc. variable definitions
8882b75dfdSjtc **---------------------------------------------------------------------
8982b75dfdSjtc */
9082b75dfdSjtc 
9182b75dfdSjtc struct stat statbuf;
9282b75dfdSjtc char    pathname[MAXPATHLEN];
9382b75dfdSjtc char    new_pathname[MAXPATHLEN];
9482b75dfdSjtc char    sp_name[MAXPATHLEN] = SPOOLDIR;
9582b75dfdSjtc char    tempstr[256];
9682b75dfdSjtc char    delims[] = " \t\r\n:()";
9782b75dfdSjtc 
9882b75dfdSjtc pr_list printers = NULL;
9982b75dfdSjtc pr_queue queue = NULL;
10082b75dfdSjtc 
10182b75dfdSjtc /*
10282b75dfdSjtc **=====================================================================
10382b75dfdSjtc **                      C O D E   S E C T I O N                       *
10482b75dfdSjtc **=====================================================================
10582b75dfdSjtc */
10682b75dfdSjtc 
10782b75dfdSjtc /*
10882b75dfdSjtc  * This is the latest word on the security check. The following
10982b75dfdSjtc  * routine "suspicious()" returns non-zero if the character string
11082b75dfdSjtc  * passed to it contains any shell metacharacters.
11182b75dfdSjtc  * Callers will typically code
11282b75dfdSjtc  *
11382b75dfdSjtc  *	if(suspicious(some_parameter)) reject();
11482b75dfdSjtc  */
11582b75dfdSjtc 
116736ba086Slukem int
117736ba086Slukem suspicious(s)
11882b75dfdSjtc 	char   *s;
11982b75dfdSjtc {
120d87f04d7Sgwr 	if (strpbrk(s, ";|&<>`'#!?*()[]^/${}\n\r\"\\:") != NULL)
12182b75dfdSjtc 		return 1;
12282b75dfdSjtc 	return 0;
12382b75dfdSjtc }
12482b75dfdSjtc 
12582b75dfdSjtc 
12682b75dfdSjtc int
12782b75dfdSjtc valid_pr(pr)
12882b75dfdSjtc 	char   *pr;
12982b75dfdSjtc {
13082b75dfdSjtc 	char   *p;
13182b75dfdSjtc 	pr_list curr;
13282b75dfdSjtc 	if (printers == NULL)
13382b75dfdSjtc 		build_pr_list();
13482b75dfdSjtc 
13582b75dfdSjtc 	if (printers == NULL)
13682b75dfdSjtc 		return (1);	/* can't tell - assume it's good */
13782b75dfdSjtc 
13882b75dfdSjtc 	p = map_printer_name(pr);
13982b75dfdSjtc 	if (p == NULL)
14082b75dfdSjtc 		return (1);	/* must be ok is maps to NULL! */
14182b75dfdSjtc 	curr = printers;
14282b75dfdSjtc 	while (curr) {
14382b75dfdSjtc 		if (!strcmp(p, curr->pn))
14482b75dfdSjtc 			return (1);
14582b75dfdSjtc 		curr = curr->pr_next;
14682b75dfdSjtc 	}
14782b75dfdSjtc 
14882b75dfdSjtc 	return (0);
14982b75dfdSjtc }
150d87f04d7Sgwr /*
151d87f04d7Sgwr  * get pathname of current directory and return to client
152d87f04d7Sgwr  *
153d87f04d7Sgwr  * Note: This runs as root on behalf of a client request.
154d87f04d7Sgwr  * As described in CERT advisory CA-96.08, be careful about
155d87f04d7Sgwr  * doing a chmod on something that could be a symlink...
156d87f04d7Sgwr  */
157d87f04d7Sgwr pirstat
158d87f04d7Sgwr pr_init(sys, pr, sp)
15982b75dfdSjtc 	char   *sys;
16082b75dfdSjtc 	char   *pr;
16182b75dfdSjtc 	char  **sp;
16282b75dfdSjtc {
16382b75dfdSjtc 	int     dir_mode = 0777;
16482b75dfdSjtc 	int     rc;
165d87f04d7Sgwr 	mode_t  oldmask;
16682b75dfdSjtc 
16782b75dfdSjtc 	*sp = &pathname[0];
16882b75dfdSjtc 	pathname[0] = '\0';
16982b75dfdSjtc 
17082b75dfdSjtc 	if (suspicious(sys) || suspicious(pr))
17182b75dfdSjtc 		return (PI_RES_FAIL);
17282b75dfdSjtc 
173d87f04d7Sgwr 	/*
174d87f04d7Sgwr 	 * Make sure the server spool directory exists.
175d87f04d7Sgwr 	 * Never create it here - the sysadmin does that.
176d87f04d7Sgwr 	 */
177d87f04d7Sgwr 	if (stat(sp_name, &statbuf) || !S_ISDIR(statbuf.st_mode))
178d87f04d7Sgwr 		goto badspool;
17982b75dfdSjtc 
180d87f04d7Sgwr 	/*
181d87f04d7Sgwr 	 * Create the client spool directory if needed.
182d87f04d7Sgwr 	 * Just do the mkdir call and ignore EEXIST.
183d87f04d7Sgwr 	 * Mode of client directory should be 777.
184d87f04d7Sgwr 	 */
1855d573dd9Sitojun 	(void) snprintf(pathname, sizeof(pathname), "%s/%s", sp_name, sys);
186d87f04d7Sgwr 	oldmask = umask(0);
18782b75dfdSjtc 	rc = mkdir(pathname, dir_mode);	/* DON'T ignore this return code */
188d87f04d7Sgwr 	umask(oldmask);
189d87f04d7Sgwr 	if ((rc < 0) && (errno != EEXIST))
190d87f04d7Sgwr 		goto badspool;
191d87f04d7Sgwr 
192d87f04d7Sgwr 	/* By this point the client spool dir should exist. */
193d87f04d7Sgwr 	if (stat(pathname, &statbuf) || !S_ISDIR(statbuf.st_mode)) {
194d87f04d7Sgwr 		/* No spool directory... */
195d87f04d7Sgwr badspool:
1965d573dd9Sitojun 		(void) snprintf(tempstr, sizeof(tempstr),
19782b75dfdSjtc 		    "rpc.pcnfsd: unable to set up spool directory %s\n",
19882b75dfdSjtc 		    pathname);
19982b75dfdSjtc 		msg_out(tempstr);
20082b75dfdSjtc 		pathname[0] = '\0';	/* null to tell client bad vibes */
20182b75dfdSjtc 		return (PI_RES_FAIL);
20282b75dfdSjtc 	}
203d87f04d7Sgwr 	/* OK, we have a spool directory. */
204d87f04d7Sgwr 	if (!valid_pr(pr)) {
20582b75dfdSjtc 		pathname[0] = '\0';	/* null to tell client bad vibes */
20682b75dfdSjtc 		return (PI_RES_NO_SUCH_PRINTER);
20782b75dfdSjtc 	}
20882b75dfdSjtc 	return (PI_RES_OK);
20982b75dfdSjtc }
210736ba086Slukem psrstat
211*0466bbb6Slukem pr_start2(sys, pr, user, fname, opts, id)
212*0466bbb6Slukem 	char   *sys;
21382b75dfdSjtc 	char   *pr;
21482b75dfdSjtc 	char   *user;
21582b75dfdSjtc 	char   *fname;
21682b75dfdSjtc 	char   *opts;
21782b75dfdSjtc 	char  **id;
21882b75dfdSjtc {
21982b75dfdSjtc 	char    snum[20];
22082b75dfdSjtc 	static char req_id[256];
22182b75dfdSjtc 	char    cmdbuf[256];
22282b75dfdSjtc 	char    resbuf[256];
22382b75dfdSjtc 	FILE   *fd;
22482b75dfdSjtc 	int     i;
22582b75dfdSjtc 	char   *xcmd;
22682b75dfdSjtc 	int     failed = 0;
22782b75dfdSjtc 
22882b75dfdSjtc #ifdef HACK_FOR_ROTATED_TRANSCRIPT
22982b75dfdSjtc 	char    scratch[512];
23082b75dfdSjtc #endif
23182b75dfdSjtc 
23282b75dfdSjtc 
233*0466bbb6Slukem 	if (suspicious(sys) ||
23482b75dfdSjtc 	    suspicious(pr) ||
23582b75dfdSjtc 	    suspicious(user) ||
23682b75dfdSjtc 	    suspicious(fname))
23782b75dfdSjtc 		return (PS_RES_FAIL);
23882b75dfdSjtc 
2395d573dd9Sitojun 	(void) snprintf(pathname, sizeof(pathname), "%s/%s/%s", sp_name,
240*0466bbb6Slukem 	    sys,
24182b75dfdSjtc 	    fname);
24282b75dfdSjtc 
24382b75dfdSjtc 	*id = &req_id[0];
24482b75dfdSjtc 	req_id[0] = '\0';
24582b75dfdSjtc 
246736ba086Slukem 	if (stat(pathname, &statbuf)) {
24782b75dfdSjtc 		/*
24882b75dfdSjtc                 **-----------------------------------------------------------------
24982b75dfdSjtc 	        ** We can't stat the file. Let's try appending '.spl' and
25082b75dfdSjtc 	        ** see if it's already in progress.
25182b75dfdSjtc                 **-----------------------------------------------------------------
25282b75dfdSjtc 	        */
25382b75dfdSjtc 
2545d573dd9Sitojun 		(void) strlcat(pathname, ".spl", sizeof(pathname));
255736ba086Slukem 		if (stat(pathname, &statbuf)) {
25682b75dfdSjtc 			/*
25782b75dfdSjtc 	                **----------------------------------------------------------------
25882b75dfdSjtc 		        ** It really doesn't exist.
25982b75dfdSjtc 	                **----------------------------------------------------------------
26082b75dfdSjtc 		        */
26182b75dfdSjtc 
26282b75dfdSjtc 
26382b75dfdSjtc 			return (PS_RES_NO_FILE);
26482b75dfdSjtc 		}
26582b75dfdSjtc 		/*
26682b75dfdSjtc                 **-------------------------------------------------------------
26782b75dfdSjtc 	        ** It is already on the way.
26882b75dfdSjtc                 **-------------------------------------------------------------
26982b75dfdSjtc 	        */
27082b75dfdSjtc 
27182b75dfdSjtc 
27282b75dfdSjtc 		return (PS_RES_ALREADY);
27382b75dfdSjtc 	}
274736ba086Slukem 	if (statbuf.st_size == 0) {
27582b75dfdSjtc 		/*
27682b75dfdSjtc                 **-------------------------------------------------------------
27782b75dfdSjtc 	        ** Null file - don't print it, just kill it.
27882b75dfdSjtc                 **-------------------------------------------------------------
27982b75dfdSjtc 	        */
28082b75dfdSjtc 		(void) unlink(pathname);
28182b75dfdSjtc 
28282b75dfdSjtc 		return (PS_RES_NULL);
28382b75dfdSjtc 	}
28482b75dfdSjtc 	/*
28582b75dfdSjtc         **-------------------------------------------------------------
28682b75dfdSjtc         ** The file is real, has some data, and is not already going out.
28782b75dfdSjtc         ** We rename it by appending '.spl' and exec "lpr" to do the
28882b75dfdSjtc         ** actual work.
28982b75dfdSjtc         **-------------------------------------------------------------
29082b75dfdSjtc         */
2915d573dd9Sitojun 	(void) strlcpy(new_pathname, pathname, sizeof(new_pathname));
2925d573dd9Sitojun 	(void) strlcat(new_pathname, ".spl", sizeof(new_pathname));
29382b75dfdSjtc 
29482b75dfdSjtc 	/*
29582b75dfdSjtc         **-------------------------------------------------------------
29682b75dfdSjtc 	** See if the new filename exists so as not to overwrite it.
29782b75dfdSjtc         **-------------------------------------------------------------
29882b75dfdSjtc 	*/
29982b75dfdSjtc 
30082b75dfdSjtc 
301736ba086Slukem 	if (!stat(new_pathname, &statbuf)) {
3025d573dd9Sitojun 		(void) strlcpy(new_pathname, pathname, sizeof(new_pathname)); /* rebuild a new name */
3035d573dd9Sitojun 		(void) snprintf(snum, sizeof(snum), "%d", rand()); /* get some number */
3045d573dd9Sitojun 		(void) strlcat(new_pathname, snum, 4);
3055d573dd9Sitojun 		(void) strlcat(new_pathname, ".spl", sizeof(new_pathname)); /* new spool file */
30682b75dfdSjtc 	}
307736ba086Slukem 	if (rename(pathname, new_pathname)) {
30882b75dfdSjtc 		/*
30982b75dfdSjtc                 **---------------------------------------------------------------
31082b75dfdSjtc 	        ** Should never happen.
31182b75dfdSjtc                 **---------------------------------------------------------------
31282b75dfdSjtc                 */
3135d573dd9Sitojun 		(void) snprintf(tempstr, sizeof(tempstr),
3145d573dd9Sitojun 		    "rpc.pcnfsd: spool file rename (%s->%s) failed.\n",
31582b75dfdSjtc 		    pathname, new_pathname);
31682b75dfdSjtc 		msg_out(tempstr);
31782b75dfdSjtc 		return (PS_RES_FAIL);
31882b75dfdSjtc 	}
319d87f04d7Sgwr 	if (*opts == 'd') {
32082b75dfdSjtc 		/*
32182b75dfdSjtc 		 **------------------------------------------------------
32282b75dfdSjtc 		 ** This is a Diablo print stream. Apply the ps630
32382b75dfdSjtc 		 ** filter with the appropriate arguments.
32482b75dfdSjtc 		 **------------------------------------------------------
32582b75dfdSjtc 		 */
326736ba086Slukem #if 0				/* XXX: Temporary fix for CERT advisory
327736ba086Slukem 				 * CA-96.08 */
32882b75dfdSjtc 		(void) run_ps630(new_pathname, opts);
329d87f04d7Sgwr #else
3305d573dd9Sitojun 		(void) snprintf(tempstr, sizeof(tempstr),
331d87f04d7Sgwr 		    "rpc.pcnfsd: ps630 filter disabled for %s\n", pathname);
332d87f04d7Sgwr 		msg_out(tempstr);
333d87f04d7Sgwr 		return (PS_RES_FAIL);
334d87f04d7Sgwr #endif
33582b75dfdSjtc 	}
33682b75dfdSjtc 	/*
33782b75dfdSjtc 	** Try to match to an aliased printer
33882b75dfdSjtc 	*/
339*0466bbb6Slukem 	xcmd = expand_alias(pr, new_pathname, user, sys);
34082b75dfdSjtc 	if (!xcmd) {
3416f885de1Sgwr #ifdef	SVR4
3426f885de1Sgwr 		/*
3436f885de1Sgwr 			 * Use the copy option so we can remove the orignal
3446f885de1Sgwr 			 * spooled nfs file from the spool directory.
3456f885de1Sgwr 			 */
3465d573dd9Sitojun 		snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/lp -c -d%s %s",
3476f885de1Sgwr 		    pr, new_pathname);
3486f885de1Sgwr #else				/* SVR4 */
3496f885de1Sgwr 		/* BSD way: lpr */
3505d573dd9Sitojun 		snprintf(cmdbuf, sizeof(cmdbuf), "%s/lpr -P%s %s",
35182b75dfdSjtc 		    LPRDIR, pr, new_pathname);
3526f885de1Sgwr #endif				/* SVR4 */
35382b75dfdSjtc 		xcmd = cmdbuf;
35482b75dfdSjtc 	}
35582b75dfdSjtc 	if ((fd = su_popen(user, xcmd, MAXTIME_FOR_PRINT)) == NULL) {
35682b75dfdSjtc 		msg_out("rpc.pcnfsd: su_popen failed");
35782b75dfdSjtc 		return (PS_RES_FAIL);
35882b75dfdSjtc 	}
35982b75dfdSjtc 	req_id[0] = '\0';	/* asume failure */
36082b75dfdSjtc 	while (fgets(resbuf, 255, fd) != NULL) {
36182b75dfdSjtc 		i = strlen(resbuf);
36282b75dfdSjtc 		if (i)
36382b75dfdSjtc 			resbuf[i - 1] = '\0';	/* trim NL */
36482b75dfdSjtc 		if (!strncmp(resbuf, "request id is ", 14))
36582b75dfdSjtc 			/* New - just the first word is needed */
3665d573dd9Sitojun 			strlcpy(req_id, strtok(&resbuf[14], delims),
3675d573dd9Sitojun 			    sizeof(req_id));
368736ba086Slukem 		else
369736ba086Slukem 			if (strembedded("disabled", resbuf))
37082b75dfdSjtc 				failed = 1;
37182b75dfdSjtc 	}
37282b75dfdSjtc 	if (su_pclose(fd) == 255)
37382b75dfdSjtc 		msg_out("rpc.pcnfsd: su_pclose alert");
37482b75dfdSjtc 	(void) unlink(new_pathname);
37582b75dfdSjtc 	return ((failed | interrupted) ? PS_RES_FAIL : PS_RES_OK);
37682b75dfdSjtc }
37782b75dfdSjtc /*
3786f885de1Sgwr  * build_pr_list: determine which printers are valid.
37982b75dfdSjtc  * on SVR4 use "lpstat -v"
3806f885de1Sgwr  * on BSD use "lpc status"
3816f885de1Sgwr  */
3826f885de1Sgwr 
3836f885de1Sgwr #ifdef	SVR4
3846f885de1Sgwr /*
3856f885de1Sgwr  * In SVR4 the command to determine which printers are
3866f885de1Sgwr  * valid is lpstat -v. The output is something like this:
3876f885de1Sgwr  *
3886f885de1Sgwr  * device for lp: /dev/lp0
3896f885de1Sgwr  * system for pcdslw: hinode
3906f885de1Sgwr  * system for bletch: hinode (as printer hisname)
3916f885de1Sgwr  *
3926f885de1Sgwr  * On SunOS using the SysV compatibility package, the output
3936f885de1Sgwr  * is more like:
3946f885de1Sgwr  *
3956f885de1Sgwr  * device for lp is /dev/lp0
3966f885de1Sgwr  * device for pcdslw is the remote printer pcdslw on hinode
3976f885de1Sgwr  * device for bletch is the remote printer hisname on hinode
3986f885de1Sgwr  *
3996f885de1Sgwr  * It is fairly simple to create logic that will handle either
4006f885de1Sgwr  * possibility:
4016f885de1Sgwr  */
4026f885de1Sgwr int
4036f885de1Sgwr build_pr_list()
4046f885de1Sgwr {
4056f885de1Sgwr 	pr_list last = NULL;
4066f885de1Sgwr 	pr_list curr = NULL;
4076f885de1Sgwr 	char    buff[256];
4086f885de1Sgwr 	FILE   *p;
4096f885de1Sgwr 	char   *cp;
4106f885de1Sgwr 	int     saw_system;
4116f885de1Sgwr 
4126f885de1Sgwr 	p = popen("lpstat -v", "r");
4136f885de1Sgwr 	if (p == NULL) {
4146f885de1Sgwr 		msg_out("rpc.pcnfsd: unable to popen() lp status");
4156f885de1Sgwr 		return (0);
4166f885de1Sgwr 	}
4176f885de1Sgwr 	while (fgets(buff, 255, p) != NULL) {
4186f885de1Sgwr 		cp = strtok(buff, delims);
4196f885de1Sgwr 		if (!cp)
4206f885de1Sgwr 			continue;
4216f885de1Sgwr 		if (!strcmp(cp, "device"))
4226f885de1Sgwr 			saw_system = 0;
423736ba086Slukem 		else
424736ba086Slukem 			if (!strcmp(cp, "system"))
4256f885de1Sgwr 				saw_system = 1;
4266f885de1Sgwr 			else
4276f885de1Sgwr 				continue;
4286f885de1Sgwr 		cp = strtok(NULL, delims);
4296f885de1Sgwr 		if (!cp || strcmp(cp, "for"))
4306f885de1Sgwr 			continue;
4316f885de1Sgwr 		cp = strtok(NULL, delims);
4326f885de1Sgwr 		if (!cp)
4336f885de1Sgwr 			continue;
4346f885de1Sgwr 		curr = (struct pr_list_item *)
4356f885de1Sgwr 		    grab(sizeof(struct pr_list_item));
4366f885de1Sgwr 
4376f885de1Sgwr 		curr->pn = strdup(cp);
4386f885de1Sgwr 		curr->device = NULL;
4396f885de1Sgwr 		curr->remhost = NULL;
4406f885de1Sgwr 		curr->cm = strdup("-");
4416f885de1Sgwr 		curr->pr_next = NULL;
4426f885de1Sgwr 
4436f885de1Sgwr 		cp = strtok(NULL, delims);
4446f885de1Sgwr 
4456f885de1Sgwr 		if (cp && !strcmp(cp, "is"))
4466f885de1Sgwr 			cp = strtok(NULL, delims);
4476f885de1Sgwr 
4486f885de1Sgwr 		if (!cp) {
4496f885de1Sgwr 			free_pr_list_item(curr);
4506f885de1Sgwr 			continue;
4516f885de1Sgwr 		}
4526f885de1Sgwr 		if (saw_system) {
4536f885de1Sgwr 			/* "system" OR "system (as printer pname)" */
4546f885de1Sgwr 			curr->remhost = strdup(cp);
4556f885de1Sgwr 			cp = strtok(NULL, delims);
4566f885de1Sgwr 			if (!cp) {
4576f885de1Sgwr 				/* simple format */
4586f885de1Sgwr 				curr->device = strdup(curr->pn);
4596f885de1Sgwr 			} else {
4606f885de1Sgwr 				/* "sys (as printer pname)" */
4616f885de1Sgwr 				if (strcmp(cp, "as")) {
4626f885de1Sgwr 					free_pr_list_item(curr);
4636f885de1Sgwr 					continue;
4646f885de1Sgwr 				}
4656f885de1Sgwr 				cp = strtok(NULL, delims);
4666f885de1Sgwr 				if (!cp || strcmp(cp, "printer")) {
4676f885de1Sgwr 					free_pr_list_item(curr);
4686f885de1Sgwr 					continue;
4696f885de1Sgwr 				}
4706f885de1Sgwr 				cp = strtok(NULL, delims);
4716f885de1Sgwr 				if (!cp) {
4726f885de1Sgwr 					free_pr_list_item(curr);
4736f885de1Sgwr 					continue;
4746f885de1Sgwr 				}
4756f885de1Sgwr 				curr->device = strdup(cp);
4766f885de1Sgwr 			}
477736ba086Slukem 		} else
478736ba086Slukem 			if (!strcmp(cp, "the")) {
4796f885de1Sgwr 				/* start of "the remote printer foo on bar" */
4806f885de1Sgwr 				cp = strtok(NULL, delims);
4816f885de1Sgwr 				if (!cp || strcmp(cp, "remote")) {
4826f885de1Sgwr 					free_pr_list_item(curr);
4836f885de1Sgwr 					continue;
4846f885de1Sgwr 				}
4856f885de1Sgwr 				cp = strtok(NULL, delims);
4866f885de1Sgwr 				if (!cp || strcmp(cp, "printer")) {
4876f885de1Sgwr 					free_pr_list_item(curr);
4886f885de1Sgwr 					continue;
4896f885de1Sgwr 				}
4906f885de1Sgwr 				cp = strtok(NULL, delims);
4916f885de1Sgwr 				if (!cp) {
4926f885de1Sgwr 					free_pr_list_item(curr);
4936f885de1Sgwr 					continue;
4946f885de1Sgwr 				}
4956f885de1Sgwr 				curr->device = strdup(cp);
4966f885de1Sgwr 				cp = strtok(NULL, delims);
4976f885de1Sgwr 				if (!cp || strcmp(cp, "on")) {
4986f885de1Sgwr 					free_pr_list_item(curr);
4996f885de1Sgwr 					continue;
5006f885de1Sgwr 				}
5016f885de1Sgwr 				cp = strtok(NULL, delims);
5026f885de1Sgwr 				if (!cp) {
5036f885de1Sgwr 					free_pr_list_item(curr);
5046f885de1Sgwr 					continue;
5056f885de1Sgwr 				}
5066f885de1Sgwr 				curr->remhost = strdup(cp);
5076f885de1Sgwr 			} else {
5086f885de1Sgwr 				/* the local name */
5096f885de1Sgwr 				curr->device = strdup(cp);
5106f885de1Sgwr 				curr->remhost = strdup("");
5116f885de1Sgwr 			}
5126f885de1Sgwr 
5136f885de1Sgwr 		if (last == NULL)
5146f885de1Sgwr 			printers = curr;
5156f885de1Sgwr 		else
5166f885de1Sgwr 			last->pr_next = curr;
5176f885de1Sgwr 		last = curr;
5186f885de1Sgwr 
5196f885de1Sgwr 	}
5206f885de1Sgwr 	(void) pclose(p);
5216f885de1Sgwr 
5226f885de1Sgwr 	/*
5236f885de1Sgwr 	 ** Now add on the virtual printers, if any
5246f885de1Sgwr 	 */
5256f885de1Sgwr 	if (last == NULL)
5266f885de1Sgwr 		printers = list_virtual_printers();
5276f885de1Sgwr 	else
5286f885de1Sgwr 		last->pr_next = list_virtual_printers();
5296f885de1Sgwr 
5306f885de1Sgwr 	return (1);
5316f885de1Sgwr }
5326f885de1Sgwr #else				/* SVR4 */
5336f885de1Sgwr 
5346f885de1Sgwr /*
5356f885de1Sgwr  * BSD way: lpc stat
53682b75dfdSjtc  */
53782b75dfdSjtc int
53882b75dfdSjtc build_pr_list()
53982b75dfdSjtc {
54082b75dfdSjtc 	pr_list last = NULL;
54182b75dfdSjtc 	pr_list curr = NULL;
54282b75dfdSjtc 	char    buff[256];
54382b75dfdSjtc 	FILE   *p;
54482b75dfdSjtc 	char   *cp;
54582b75dfdSjtc 
5465d573dd9Sitojun 	snprintf(buff, sizeof(buff), "%s/lpc status", LPCDIR);
54782b75dfdSjtc 	p = popen(buff, "r");
54882b75dfdSjtc 	if (p == NULL) {
54982b75dfdSjtc 		msg_out("rpc.pcnfsd: unable to popen lpc stat");
55082b75dfdSjtc 		return (0);
55182b75dfdSjtc 	}
55282b75dfdSjtc 	while (fgets(buff, 255, p) != NULL) {
553c4670c4eSdsl 		if (isspace((unsigned char)buff[0]))
55482b75dfdSjtc 			continue;
55582b75dfdSjtc 
55682b75dfdSjtc 		if ((cp = strtok(buff, delims)) == NULL)
55782b75dfdSjtc 			continue;
55882b75dfdSjtc 
55982b75dfdSjtc 		curr = (struct pr_list_item *)
56082b75dfdSjtc 		    grab(sizeof(struct pr_list_item));
56182b75dfdSjtc 
56282b75dfdSjtc 		/* XXX - Should distinguish remote printers. */
56382b75dfdSjtc 		curr->pn = strdup(cp);
56482b75dfdSjtc 		curr->device = strdup(cp);
56582b75dfdSjtc 		curr->remhost = strdup("");
56682b75dfdSjtc 		curr->cm = strdup("-");
56782b75dfdSjtc 		curr->pr_next = NULL;
56882b75dfdSjtc 
56982b75dfdSjtc 		if (last == NULL)
57082b75dfdSjtc 			printers = curr;
57182b75dfdSjtc 		else
57282b75dfdSjtc 			last->pr_next = curr;
57382b75dfdSjtc 		last = curr;
57482b75dfdSjtc 
57582b75dfdSjtc 	}
57682b75dfdSjtc 	(void) fclose(p);
57782b75dfdSjtc 
57882b75dfdSjtc 	/*
57982b75dfdSjtc 	 ** Now add on the virtual printers, if any
58082b75dfdSjtc 	 */
58182b75dfdSjtc 	if (last == NULL)
58282b75dfdSjtc 		printers = list_virtual_printers();
58382b75dfdSjtc 	else
58482b75dfdSjtc 		last->pr_next = list_virtual_printers();
58582b75dfdSjtc 
58682b75dfdSjtc 	return (1);
58782b75dfdSjtc }
5886f885de1Sgwr #endif				/* SVR4 */
5896f885de1Sgwr 
590736ba086Slukem void   *
591736ba086Slukem grab(n)
59282b75dfdSjtc 	int     n;
59382b75dfdSjtc {
59482b75dfdSjtc 	void   *p;
59582b75dfdSjtc 
59682b75dfdSjtc 	p = (void *) malloc(n);
59782b75dfdSjtc 	if (p == NULL) {
59882b75dfdSjtc 		msg_out("rpc.pcnfsd: malloc failure");
59982b75dfdSjtc 		exit(1);
60082b75dfdSjtc 	}
60182b75dfdSjtc 	return (p);
60282b75dfdSjtc }
60382b75dfdSjtc 
60482b75dfdSjtc void
60582b75dfdSjtc free_pr_list_item(curr)
60682b75dfdSjtc 	pr_list curr;
60782b75dfdSjtc {
60882b75dfdSjtc 	if (curr->pn)
60982b75dfdSjtc 		free(curr->pn);
61082b75dfdSjtc 	if (curr->device)
61182b75dfdSjtc 		free(curr->device);
61282b75dfdSjtc 	if (curr->remhost)
61382b75dfdSjtc 		free(curr->remhost);
61482b75dfdSjtc 	if (curr->cm)
61582b75dfdSjtc 		free(curr->cm);
61682b75dfdSjtc 	if (curr->pr_next)
61782b75dfdSjtc 		free_pr_list_item(curr->pr_next);	/* recurse */
61882b75dfdSjtc 	free(curr);
61982b75dfdSjtc }
62082b75dfdSjtc /*
6216f885de1Sgwr  * build_pr_queue:  used to show the print queue.
6226f885de1Sgwr  *
6236f885de1Sgwr  * Note that the first thing we do is to discard any
6246f885de1Sgwr  * existing queue.
62582b75dfdSjtc  */
6266f885de1Sgwr #ifdef SVR4
6276f885de1Sgwr 
6286f885de1Sgwr /*
6296f885de1Sgwr ** In SVR4 the command to list the print jobs for printer
6306f885de1Sgwr ** lp is "lpstat lp" (or, equivalently, "lpstat -p lp").
6316f885de1Sgwr ** The output looks like this:
6326f885de1Sgwr **
6336f885de1Sgwr ** lp-2                    root               939   Jul 10 21:56
6346f885de1Sgwr ** lp-5                    geoff               15   Jul 12 23:23
6356f885de1Sgwr ** lp-6                    geoff               15   Jul 12 23:23
6366f885de1Sgwr **
6376f885de1Sgwr ** If the first job is actually printing the first line
6386f885de1Sgwr ** is modified, as follows:
6396f885de1Sgwr **
6406f885de1Sgwr ** lp-2                    root               939   Jul 10 21:56 on lp
6416f885de1Sgwr **
6426f885de1Sgwr ** I don't yet have any info on what it looks like if the printer
6436f885de1Sgwr ** is remote and we're spooling over the net. However for
6446f885de1Sgwr ** the purposes of rpc.pcnfsd we can simply say that field 1 is the
6456f885de1Sgwr ** job ID, field 2 is the submitter, and field 3 is the size.
6466f885de1Sgwr ** We can check for the presence of the string " on " in the
6476f885de1Sgwr ** first record to determine if we should count it as rank 0 or rank 1,
6486f885de1Sgwr ** but it won't hurt if we get it wrong.
6496f885de1Sgwr **/
6506f885de1Sgwr 
6516f885de1Sgwr pirstat
6526f885de1Sgwr build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
6536f885de1Sgwr 	printername pn;
6546f885de1Sgwr 	username user;
6556f885de1Sgwr 	int     just_mine;
6566f885de1Sgwr 	int    *p_qlen;
6576f885de1Sgwr 	int    *p_qshown;
6586f885de1Sgwr {
6596f885de1Sgwr 	pr_queue last = NULL;
6606f885de1Sgwr 	pr_queue curr = NULL;
6616f885de1Sgwr 	char    buff[256];
6626f885de1Sgwr 	FILE   *p;
6636f885de1Sgwr 	char   *owner;
6646f885de1Sgwr 	char   *job;
6656f885de1Sgwr 	char   *totsize;
6666f885de1Sgwr 
6676f885de1Sgwr 	if (queue) {
6686f885de1Sgwr 		free_pr_queue_item(queue);
6696f885de1Sgwr 		queue = NULL;
6706f885de1Sgwr 	}
6716f885de1Sgwr 	*p_qlen = 0;
6726f885de1Sgwr 	*p_qshown = 0;
6736f885de1Sgwr 
6746f885de1Sgwr 	pn = map_printer_name(pn);
6756f885de1Sgwr 	if (pn == NULL || !valid_pr(pn) || suspicious(pn))
6766f885de1Sgwr 		return (PI_RES_NO_SUCH_PRINTER);
6776f885de1Sgwr 
6785d573dd9Sitojun 	snprintf(buff, sizeof(buff), "/usr/bin/lpstat %s", pn);
6796f885de1Sgwr 	p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
6806f885de1Sgwr 	if (p == NULL) {
6816f885de1Sgwr 		msg_out("rpc.pcnfsd: unable to popen() lpstat queue query");
6826f885de1Sgwr 		return (PI_RES_FAIL);
6836f885de1Sgwr 	}
6846f885de1Sgwr 	while (fgets(buff, 255, p) != NULL) {
6856f885de1Sgwr 		job = strtok(buff, delims);
6866f885de1Sgwr 		if (!job)
6876f885de1Sgwr 			continue;
6886f885de1Sgwr 
6896f885de1Sgwr 		owner = strtok(NULL, delims);
6906f885de1Sgwr 		if (!owner)
6916f885de1Sgwr 			continue;
6926f885de1Sgwr 
6936f885de1Sgwr 		totsize = strtok(NULL, delims);
6946f885de1Sgwr 		if (!totsize)
6956f885de1Sgwr 			continue;
6966f885de1Sgwr 
6976f885de1Sgwr 		*p_qlen += 1;
6986f885de1Sgwr 
6996f885de1Sgwr 		if (*p_qshown > QMAX)
7006f885de1Sgwr 			continue;
7016f885de1Sgwr 
702736ba086Slukem 		if (just_mine && strcasecmp(owner, user))
7036f885de1Sgwr 			continue;
7046f885de1Sgwr 
7056f885de1Sgwr 		*p_qshown += 1;
7066f885de1Sgwr 
7076f885de1Sgwr 		curr = (struct pr_queue_item *)
7086f885de1Sgwr 		    grab(sizeof(struct pr_queue_item));
7096f885de1Sgwr 
7106f885de1Sgwr 		curr->position = *p_qlen;
7116f885de1Sgwr 		curr->id = strdup(job);
7126f885de1Sgwr 		curr->size = strdup(totsize);
7136f885de1Sgwr 		curr->status = strdup("");
7146f885de1Sgwr 		curr->system = strdup("");
7156f885de1Sgwr 		curr->user = strdup(owner);
7166f885de1Sgwr 		curr->file = strdup("");
7176f885de1Sgwr 		curr->cm = strdup("-");
7186f885de1Sgwr 		curr->pr_next = NULL;
7196f885de1Sgwr 
7206f885de1Sgwr 		if (last == NULL)
7216f885de1Sgwr 			queue = curr;
7226f885de1Sgwr 		else
7236f885de1Sgwr 			last->pr_next = curr;
7246f885de1Sgwr 		last = curr;
7256f885de1Sgwr 
7266f885de1Sgwr 	}
7276f885de1Sgwr 	(void) su_pclose(p);
7286f885de1Sgwr 	return (PI_RES_OK);
7296f885de1Sgwr }
7306f885de1Sgwr #else				/* SVR4 */
73182b75dfdSjtc 
73282b75dfdSjtc pirstat
73382b75dfdSjtc build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
73482b75dfdSjtc 	printername pn;
73582b75dfdSjtc 	username user;
73682b75dfdSjtc 	int     just_mine;
73782b75dfdSjtc 	int    *p_qlen;
73882b75dfdSjtc 	int    *p_qshown;
73982b75dfdSjtc {
74082b75dfdSjtc 	pr_queue last = NULL;
74182b75dfdSjtc 	pr_queue curr = NULL;
74282b75dfdSjtc 	char    buff[256];
74382b75dfdSjtc 	FILE   *p;
74482b75dfdSjtc 	char   *cp;
74582b75dfdSjtc 	int     i;
74682b75dfdSjtc 	char   *rank;
74782b75dfdSjtc 	char   *owner;
74882b75dfdSjtc 	char   *job;
74982b75dfdSjtc 	char   *files;
75082b75dfdSjtc 	char   *totsize;
75182b75dfdSjtc 
75282b75dfdSjtc 	if (queue) {
75382b75dfdSjtc 		free_pr_queue_item(queue);
75482b75dfdSjtc 		queue = NULL;
75582b75dfdSjtc 	}
75682b75dfdSjtc 	*p_qlen = 0;
75782b75dfdSjtc 	*p_qshown = 0;
75882b75dfdSjtc 	pn = map_printer_name(pn);
75982b75dfdSjtc 	if (pn == NULL || suspicious(pn))
76082b75dfdSjtc 		return (PI_RES_NO_SUCH_PRINTER);
76182b75dfdSjtc 
7625d573dd9Sitojun 	snprintf(buff, sizeof(buff), "%s/lpq -P%s", LPRDIR, pn);
76382b75dfdSjtc 
76482b75dfdSjtc 	p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
76582b75dfdSjtc 	if (p == NULL) {
76682b75dfdSjtc 		msg_out("rpc.pcnfsd: unable to popen() lpq");
76782b75dfdSjtc 		return (PI_RES_FAIL);
76882b75dfdSjtc 	}
76982b75dfdSjtc 	while (fgets(buff, 255, p) != NULL) {
77082b75dfdSjtc 		i = strlen(buff) - 1;
77182b75dfdSjtc 		buff[i] = '\0';	/* zap trailing NL */
77282b75dfdSjtc 		if (i < SIZECOL)
77382b75dfdSjtc 			continue;
774736ba086Slukem 		if (!strncasecmp(buff, "rank", 4))
77582b75dfdSjtc 			continue;
77682b75dfdSjtc 
77782b75dfdSjtc 		totsize = &buff[SIZECOL - 1];
77882b75dfdSjtc 		files = &buff[FILECOL - 1];
77982b75dfdSjtc 		cp = totsize;
78082b75dfdSjtc 		cp--;
781c4670c4eSdsl 		while (cp > files && isspace((unsigned char)*cp))
78282b75dfdSjtc 			*cp-- = '\0';
78382b75dfdSjtc 
78482b75dfdSjtc 		buff[FILECOL - 2] = '\0';
78582b75dfdSjtc 
78682b75dfdSjtc 		cp = strtok(buff, delims);
78782b75dfdSjtc 		if (!cp)
78882b75dfdSjtc 			continue;
78982b75dfdSjtc 		rank = cp;
79082b75dfdSjtc 
79182b75dfdSjtc 		cp = strtok(NULL, delims);
79282b75dfdSjtc 		if (!cp)
79382b75dfdSjtc 			continue;
79482b75dfdSjtc 		owner = cp;
79582b75dfdSjtc 
79682b75dfdSjtc 		cp = strtok(NULL, delims);
79782b75dfdSjtc 		if (!cp)
79882b75dfdSjtc 			continue;
79982b75dfdSjtc 		job = cp;
80082b75dfdSjtc 
80182b75dfdSjtc 		*p_qlen += 1;
80282b75dfdSjtc 
80382b75dfdSjtc 		if (*p_qshown > QMAX)
80482b75dfdSjtc 			continue;
80582b75dfdSjtc 
806736ba086Slukem 		if (just_mine && strcasecmp(owner, user))
80782b75dfdSjtc 			continue;
80882b75dfdSjtc 
80982b75dfdSjtc 		*p_qshown += 1;
81082b75dfdSjtc 
81182b75dfdSjtc 		curr = (struct pr_queue_item *)
81282b75dfdSjtc 		    grab(sizeof(struct pr_queue_item));
81382b75dfdSjtc 
81482b75dfdSjtc 		curr->position = atoi(rank);	/* active -> 0 */
81582b75dfdSjtc 		curr->id = strdup(job);
81682b75dfdSjtc 		curr->size = strdup(totsize);
81782b75dfdSjtc 		curr->status = strdup(rank);
81882b75dfdSjtc 		curr->system = strdup("");
81982b75dfdSjtc 		curr->user = strdup(owner);
82082b75dfdSjtc 		curr->file = strdup(files);
82182b75dfdSjtc 		curr->cm = strdup("-");
82282b75dfdSjtc 		curr->pr_next = NULL;
82382b75dfdSjtc 
82482b75dfdSjtc 		if (last == NULL)
82582b75dfdSjtc 			queue = curr;
82682b75dfdSjtc 		else
82782b75dfdSjtc 			last->pr_next = curr;
82882b75dfdSjtc 		last = curr;
82982b75dfdSjtc 
83082b75dfdSjtc 	}
83182b75dfdSjtc 	(void) su_pclose(p);
83282b75dfdSjtc 	return (PI_RES_OK);
83382b75dfdSjtc }
8346f885de1Sgwr #endif				/* SVR4 */
8356f885de1Sgwr 
83682b75dfdSjtc void
83782b75dfdSjtc free_pr_queue_item(curr)
83882b75dfdSjtc 	pr_queue curr;
83982b75dfdSjtc {
84082b75dfdSjtc 	if (curr->id)
84182b75dfdSjtc 		free(curr->id);
84282b75dfdSjtc 	if (curr->size)
84382b75dfdSjtc 		free(curr->size);
84482b75dfdSjtc 	if (curr->status)
84582b75dfdSjtc 		free(curr->status);
84682b75dfdSjtc 	if (curr->system)
84782b75dfdSjtc 		free(curr->system);
84882b75dfdSjtc 	if (curr->user)
84982b75dfdSjtc 		free(curr->user);
85082b75dfdSjtc 	if (curr->file)
85182b75dfdSjtc 		free(curr->file);
85282b75dfdSjtc 	if (curr->cm)
85382b75dfdSjtc 		free(curr->cm);
85482b75dfdSjtc 	if (curr->pr_next)
85582b75dfdSjtc 		free_pr_queue_item(curr->pr_next);	/* recurse */
85682b75dfdSjtc 	free(curr);
85782b75dfdSjtc }
8586f885de1Sgwr #ifdef SVR4
85982b75dfdSjtc 
8606f885de1Sgwr /*
8616f885de1Sgwr ** New - SVR4 printer status handling.
8626f885de1Sgwr **
8636f885de1Sgwr ** The command we'll use for checking the status of printer "lp"
8646f885de1Sgwr ** is "lpstat -a lp -p lp". Here are some sample outputs:
8656f885de1Sgwr **
8666f885de1Sgwr **
8676f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8686f885de1Sgwr ** printer lp disabled since Thu Feb 21 22:52:36 EST 1991. available.
8696f885de1Sgwr ** 	new printer
8706f885de1Sgwr ** ---
8716f885de1Sgwr ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
8726f885de1Sgwr ** 	unknown reason
8736f885de1Sgwr ** printer pcdslw disabled since Fri Jul 12 22:15:37 EDT 1991. available.
8746f885de1Sgwr ** 	new printer
8756f885de1Sgwr ** ---
8766f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8776f885de1Sgwr ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
8786f885de1Sgwr ** ---
8796f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8806f885de1Sgwr ** printer lp now printing lp-2. enabled since Sat Jul 13 12:02:17 EDT 1991. available.
8816f885de1Sgwr ** ---
8826f885de1Sgwr ** lp accepting requests since Wed Jul 10 21:49:25 EDT 1991
8836f885de1Sgwr ** printer lp disabled since Sat Jul 13 12:05:20 EDT 1991. available.
8846f885de1Sgwr ** 	unknown reason
8856f885de1Sgwr ** ---
8866f885de1Sgwr ** pcdslw not accepting requests since Fri Jul 12 22:30:00 EDT 1991 -
8876f885de1Sgwr ** 	unknown reason
8886f885de1Sgwr ** printer pcdslw is idle. enabled since Sat Jul 13 12:05:28 EDT 1991. available.
8896f885de1Sgwr **
8906f885de1Sgwr ** Note that these are actual outputs. The format (which is totally
8916f885de1Sgwr ** different from the lpstat in SunOS) seems to break down as
8926f885de1Sgwr ** follows:
8936f885de1Sgwr ** (1) The first line has the form "printername [not] accepting requests,,,"
8946f885de1Sgwr **    This is trivial to decode.
8956f885de1Sgwr ** (2) The second line has several forms, all beginning "printer printername":
8966f885de1Sgwr ** (2.1) "... disabled"
8976f885de1Sgwr ** (2.2) "... is idle"
8986f885de1Sgwr ** (2.3) "... now printing jobid"
8996f885de1Sgwr ** The "available" comment seems to be meaningless. The next line
9006f885de1Sgwr ** is the "reason" code which the operator can supply when issuing
9016f885de1Sgwr ** a "disable" or "reject" command.
9026f885de1Sgwr ** Note that there is no way to check the number of entries in the
9036f885de1Sgwr ** queue except to ask for the queue and count them.
9046f885de1Sgwr */
90582b75dfdSjtc 
90682b75dfdSjtc pirstat
90782b75dfdSjtc get_pr_status(pn, avail, printing, qlen, needs_operator, status)
90882b75dfdSjtc 	printername pn;
90982b75dfdSjtc 	bool_t *avail;
91082b75dfdSjtc 	bool_t *printing;
91182b75dfdSjtc 	int    *qlen;
91282b75dfdSjtc 	bool_t *needs_operator;
91382b75dfdSjtc 	char   *status;
91482b75dfdSjtc {
9156f885de1Sgwr 	char    buff[256];
9166f885de1Sgwr 	char    cmd[64];
9176f885de1Sgwr 	FILE   *p;
9186f885de1Sgwr 	int     n;
9196f885de1Sgwr 	pirstat stat = PI_RES_NO_SUCH_PRINTER;
9206f885de1Sgwr 
9216f885de1Sgwr 	/* assume the worst */
9226f885de1Sgwr 	*avail = FALSE;
9236f885de1Sgwr 	*printing = FALSE;
9246f885de1Sgwr 	*needs_operator = FALSE;
9256f885de1Sgwr 	*qlen = 0;
9266f885de1Sgwr 	*status = '\0';
9276f885de1Sgwr 
9286f885de1Sgwr 	pn = map_printer_name(pn);
9296f885de1Sgwr 	if (pn == NULL || !valid_pr(pn) || suspicious(pn))
9306f885de1Sgwr 		return (PI_RES_NO_SUCH_PRINTER);
9316f885de1Sgwr 	n = strlen(pn);
9326f885de1Sgwr 
9335d573dd9Sitojun 	snprintf(cmd, sizeof(cmd), "/usr/bin/lpstat -a %s -p %s", pn, pn);
9346f885de1Sgwr 
9356f885de1Sgwr 	p = popen(cmd, "r");
9366f885de1Sgwr 	if (p == NULL) {
9376f885de1Sgwr 		msg_out("rpc.pcnfsd: unable to popen() lp status");
9386f885de1Sgwr 		return (PI_RES_FAIL);
9396f885de1Sgwr 	}
9406f885de1Sgwr 	stat = PI_RES_OK;
9416f885de1Sgwr 
9426f885de1Sgwr 	while (fgets(buff, 255, p) != NULL) {
9436f885de1Sgwr 		if (!strncmp(buff, pn, n)) {
9446f885de1Sgwr 			if (!strstr(buff, "not accepting"))
9456f885de1Sgwr 				*avail = TRUE;
9466f885de1Sgwr 			continue;
9476f885de1Sgwr 		}
9486f885de1Sgwr 		if (!strncmp(buff, "printer ", 8)) {
9496f885de1Sgwr 			if (!strstr(buff, "disabled"))
9506f885de1Sgwr 				*printing = TRUE;
9516f885de1Sgwr 			if (strstr(buff, "printing"))
9525d573dd9Sitojun 				strlcpy(status, "printing", sizeof9status));
953736ba086Slukem 			else
954736ba086Slukem 				if (strstr(buff, "idle"))
9555d573dd9Sitojun 					strlcpy(status, "idle", sizeof(status));
9566f885de1Sgwr 			continue;
9576f885de1Sgwr 		}
9586f885de1Sgwr 		if (!strncmp(buff, "UX:", 3)) {
9596f885de1Sgwr 			stat = PI_RES_NO_SUCH_PRINTER;
9606f885de1Sgwr 		}
9616f885de1Sgwr 	}
9626f885de1Sgwr 	(void) pclose(p);
9636f885de1Sgwr 	return (stat);
9646f885de1Sgwr }
9656f885de1Sgwr #else				/* SVR4 */
9666f885de1Sgwr 
9676f885de1Sgwr /*
9686f885de1Sgwr  * BSD way: lpc status
9696f885de1Sgwr  */
9706f885de1Sgwr pirstat
9716f885de1Sgwr get_pr_status(pn, avail, printing, qlen, needs_operator, status)
9726f885de1Sgwr 	printername pn;
9736f885de1Sgwr 	bool_t *avail;
9746f885de1Sgwr 	bool_t *printing;
9756f885de1Sgwr 	int    *qlen;
9766f885de1Sgwr 	bool_t *needs_operator;
9776f885de1Sgwr 	char   *status;
9786f885de1Sgwr {
97982b75dfdSjtc 	char    cmd[128];
98082b75dfdSjtc 	char    buff[256];
98182b75dfdSjtc 	char    buff2[256];
98282b75dfdSjtc 	char    pname[64];
98382b75dfdSjtc 	FILE   *p;
98482b75dfdSjtc 	char   *cp;
98582b75dfdSjtc 	char   *cp1;
98682b75dfdSjtc 	char   *cp2;
98782b75dfdSjtc 	int     n;
988*0466bbb6Slukem 	pirstat pstat = PI_RES_NO_SUCH_PRINTER;
98982b75dfdSjtc 
99082b75dfdSjtc 	/* assume the worst */
99182b75dfdSjtc 	*avail = FALSE;
99282b75dfdSjtc 	*printing = FALSE;
99382b75dfdSjtc 	*needs_operator = FALSE;
99482b75dfdSjtc 	*qlen = 0;
99582b75dfdSjtc 	*status = '\0';
99682b75dfdSjtc 
99782b75dfdSjtc 	pn = map_printer_name(pn);
99882b75dfdSjtc 	if (pn == NULL || suspicious(pn))
99982b75dfdSjtc 		return (PI_RES_NO_SUCH_PRINTER);
100082b75dfdSjtc 
10015d573dd9Sitojun 	snprintf(pname, sizeof(pname), "%s:", pn);
100282b75dfdSjtc 	n = strlen(pname);
100382b75dfdSjtc 
10045d573dd9Sitojun 	snprintf(cmd, sizeof(cmd), "%s/lpc status %s", LPCDIR, pn);
100582b75dfdSjtc 	p = popen(cmd, "r");
100682b75dfdSjtc 	if (p == NULL) {
100782b75dfdSjtc 		msg_out("rpc.pcnfsd: unable to popen() lp status");
100882b75dfdSjtc 		return (PI_RES_FAIL);
100982b75dfdSjtc 	}
101082b75dfdSjtc 	while (fgets(buff, 255, p) != NULL) {
101182b75dfdSjtc 		if (strncmp(buff, pname, n))
101282b75dfdSjtc 			continue;
101382b75dfdSjtc /*
101482b75dfdSjtc ** We have a match. The only failure now is PI_RES_FAIL if
101582b75dfdSjtc ** lpstat output cannot be decoded
101682b75dfdSjtc */
1017*0466bbb6Slukem 		pstat = PI_RES_FAIL;
101882b75dfdSjtc /*
101982b75dfdSjtc ** The next four lines are usually if the form
102082b75dfdSjtc **
102182b75dfdSjtc **     queuing is [enabled|disabled]
102282b75dfdSjtc **     printing is [enabled|disabled]
102382b75dfdSjtc **     [no entries | N entr[y|ies] in spool area]
102482b75dfdSjtc **     <status message, may include the word "attention">
102582b75dfdSjtc */
1026c4670c4eSdsl 		while (fgets(buff, 255, p) != NULL && isspace((unsigned char)buff[0])) {
102782b75dfdSjtc 			cp = buff;
1028c4670c4eSdsl 			while (isspace((unsigned char)*cp))
102982b75dfdSjtc 				cp++;
103082b75dfdSjtc 			if (*cp == '\0')
103182b75dfdSjtc 				break;
103282b75dfdSjtc 			cp1 = cp;
103382b75dfdSjtc 			cp2 = buff2;
103482b75dfdSjtc 			while (*cp1 && *cp1 != '\n') {
1035c4670c4eSdsl 				*cp2++ = tolower((unsigned char)*cp1);
103682b75dfdSjtc 				cp1++;
103782b75dfdSjtc 			}
103882b75dfdSjtc 			*cp1 = '\0';
103982b75dfdSjtc 			*cp2 = '\0';
104082b75dfdSjtc /*
104182b75dfdSjtc ** Now buff2 has a lower-cased copy and cp points at the original;
104282b75dfdSjtc ** both are null terminated without any newline
104382b75dfdSjtc */
104482b75dfdSjtc 			if (!strncmp(buff2, "queuing", 7)) {
104582b75dfdSjtc 				*avail = (strstr(buff2, "enabled") != NULL);
104682b75dfdSjtc 				continue;
104782b75dfdSjtc 			}
104882b75dfdSjtc 			if (!strncmp(buff2, "printing", 8)) {
104982b75dfdSjtc 				*printing = (strstr(buff2, "enabled") != NULL);
105082b75dfdSjtc 				continue;
105182b75dfdSjtc 			}
1052c4670c4eSdsl 			if (isdigit((unsigned char)buff2[0]) && (strstr(buff2, "entr") != NULL)) {
105382b75dfdSjtc 
105482b75dfdSjtc 				*qlen = atoi(buff2);
105582b75dfdSjtc 				continue;
105682b75dfdSjtc 			}
105782b75dfdSjtc 			if (strstr(buff2, "attention") != NULL ||
105882b75dfdSjtc 			    strstr(buff2, "error") != NULL)
105982b75dfdSjtc 				*needs_operator = TRUE;
106082b75dfdSjtc 			if (*needs_operator || strstr(buff2, "waiting") != NULL)
10615d573dd9Sitojun 				strlcpy(status, cp, sizeof(status));
106282b75dfdSjtc 		}
1063*0466bbb6Slukem 		pstat = PI_RES_OK;
106482b75dfdSjtc 		break;
106582b75dfdSjtc 	}
106682b75dfdSjtc 	(void) pclose(p);
1067*0466bbb6Slukem 	return (pstat);
106882b75dfdSjtc }
10696f885de1Sgwr #endif				/* SVR4 */
107082b75dfdSjtc 
10716f885de1Sgwr /*
10726f885de1Sgwr  * pr_cancel: cancel a print job
10736f885de1Sgwr  */
10746f885de1Sgwr #ifdef SVR4
10756f885de1Sgwr 
10766f885de1Sgwr /*
10776f885de1Sgwr ** For SVR4 we have to be prepared for the following kinds of output:
10786f885de1Sgwr **
10796f885de1Sgwr ** # cancel lp-6
10806f885de1Sgwr ** request "lp-6" cancelled
10816f885de1Sgwr ** # cancel lp-33
10826f885de1Sgwr ** UX:cancel: WARNING: Request "lp-33" doesn't exist.
10836f885de1Sgwr ** # cancel foo-88
10846f885de1Sgwr ** UX:cancel: WARNING: Request "foo-88" doesn't exist.
10856f885de1Sgwr ** # cancel foo
10866f885de1Sgwr ** UX:cancel: WARNING: "foo" is not a request id or a printer.
10876f885de1Sgwr **             TO FIX: Cancel requests by id or by
10886f885de1Sgwr **                     name of printer where printing.
10896f885de1Sgwr ** # su geoff
10906f885de1Sgwr ** $ cancel lp-2
10916f885de1Sgwr ** UX:cancel: WARNING: Can't cancel request "lp-2".
10926f885de1Sgwr **             TO FIX: You are not allowed to cancel
10936f885de1Sgwr **                     another's request.
10946f885de1Sgwr **
10956f885de1Sgwr ** There are probably other variations for remote printers.
10966f885de1Sgwr ** Basically, if the reply begins with the string
10976f885de1Sgwr **          "UX:cancel: WARNING: "
10986f885de1Sgwr ** we can strip this off and look for one of the following
10996f885de1Sgwr ** (1) 'R' - should be part of "Request "xxxx" doesn't exist."
11006f885de1Sgwr ** (2) '"' - should be start of ""foo" is not a request id or..."
11016f885de1Sgwr ** (3) 'C' - should be start of "Can't cancel request..."
11026f885de1Sgwr **
11036f885de1Sgwr ** The fly in the ointment: all of this can change if these
11046f885de1Sgwr ** messages are localized..... :-(
11056f885de1Sgwr */
1106736ba086Slukem pcrstat
1107736ba086Slukem pr_cancel(pr, user, id)
11086f885de1Sgwr 	char   *pr;
11096f885de1Sgwr 	char   *user;
11106f885de1Sgwr 	char   *id;
11116f885de1Sgwr {
11126f885de1Sgwr 	char    cmdbuf[256];
11136f885de1Sgwr 	char    resbuf[256];
11146f885de1Sgwr 	FILE   *fd;
11156f885de1Sgwr 	pcrstat stat = PC_RES_NO_SUCH_JOB;
11166f885de1Sgwr 
11176f885de1Sgwr 	pr = map_printer_name(pr);
11186f885de1Sgwr 	if (pr == NULL || suspicious(pr))
11196f885de1Sgwr 		return (PC_RES_NO_SUCH_PRINTER);
11206f885de1Sgwr 	if (suspicious(id))
11216f885de1Sgwr 		return (PC_RES_NO_SUCH_JOB);
11226f885de1Sgwr 
11235d573dd9Sitojun 	snprintf(cmdbuf, sizeof(cmdbuf), "/usr/bin/cancel %s", id);
11246f885de1Sgwr 	if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
11256f885de1Sgwr 		msg_out("rpc.pcnfsd: su_popen failed");
11266f885de1Sgwr 		return (PC_RES_FAIL);
11276f885de1Sgwr 	}
11286f885de1Sgwr 	if (fgets(resbuf, 255, fd) == NULL)
11296f885de1Sgwr 		stat = PC_RES_FAIL;
1130736ba086Slukem 	else
1131736ba086Slukem 		if (!strstr(resbuf, "UX:"))
11326f885de1Sgwr 			stat = PC_RES_OK;
1133736ba086Slukem 		else
1134736ba086Slukem 			if (strstr(resbuf, "doesn't exist"))
11356f885de1Sgwr 				stat = PC_RES_NO_SUCH_JOB;
1136736ba086Slukem 			else
1137736ba086Slukem 				if (strstr(resbuf, "not a request id"))
11386f885de1Sgwr 					stat = PC_RES_NO_SUCH_JOB;
1139736ba086Slukem 				else
1140736ba086Slukem 					if (strstr(resbuf, "Can't cancel request"))
11416f885de1Sgwr 						stat = PC_RES_NOT_OWNER;
1142736ba086Slukem 					else
1143736ba086Slukem 						stat = PC_RES_FAIL;
11446f885de1Sgwr 
11456f885de1Sgwr 	if (su_pclose(fd) == 255)
11466f885de1Sgwr 		msg_out("rpc.pcnfsd: su_pclose alert");
11476f885de1Sgwr 	return (stat);
11486f885de1Sgwr }
11496f885de1Sgwr #else				/* SVR4 */
11506f885de1Sgwr 
11516f885de1Sgwr /*
11526f885de1Sgwr  * BSD way: lprm
11536f885de1Sgwr  */
1154736ba086Slukem pcrstat
1155736ba086Slukem pr_cancel(pr, user, id)
115682b75dfdSjtc 	char   *pr;
115782b75dfdSjtc 	char   *user;
115882b75dfdSjtc 	char   *id;
115982b75dfdSjtc {
116082b75dfdSjtc 	char    cmdbuf[256];
116182b75dfdSjtc 	char    resbuf[256];
116282b75dfdSjtc 	FILE   *fd;
116382b75dfdSjtc 	int     i;
1164*0466bbb6Slukem 	pcrstat pstat = PC_RES_NO_SUCH_JOB;
116582b75dfdSjtc 
116682b75dfdSjtc 	pr = map_printer_name(pr);
116782b75dfdSjtc 	if (pr == NULL || suspicious(pr))
116882b75dfdSjtc 		return (PC_RES_NO_SUCH_PRINTER);
116982b75dfdSjtc 	if (suspicious(id))
117082b75dfdSjtc 		return (PC_RES_NO_SUCH_JOB);
117182b75dfdSjtc 
11725d573dd9Sitojun 	snprintf(cmdbuf, sizeof(cmdbuf), "%s/lprm -P%s %s", LPRDIR, pr, id);
117382b75dfdSjtc 	if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
117482b75dfdSjtc 		msg_out("rpc.pcnfsd: su_popen failed");
117582b75dfdSjtc 		return (PC_RES_FAIL);
117682b75dfdSjtc 	}
117782b75dfdSjtc 	while (fgets(resbuf, 255, fd) != NULL) {
117882b75dfdSjtc 		i = strlen(resbuf);
117982b75dfdSjtc 		if (i)
118082b75dfdSjtc 			resbuf[i - 1] = '\0';	/* trim NL */
118182b75dfdSjtc 		if (strstr(resbuf, "dequeued") != NULL)
1182*0466bbb6Slukem 			pstat = PC_RES_OK;
118382b75dfdSjtc 		if (strstr(resbuf, "unknown printer") != NULL)
1184*0466bbb6Slukem 			pstat = PC_RES_NO_SUCH_PRINTER;
118582b75dfdSjtc 		if (strstr(resbuf, "Permission denied") != NULL)
1186*0466bbb6Slukem 			pstat = PC_RES_NOT_OWNER;
118782b75dfdSjtc 	}
118882b75dfdSjtc 	if (su_pclose(fd) == 255)
118982b75dfdSjtc 		msg_out("rpc.pcnfsd: su_pclose alert");
1190*0466bbb6Slukem 	return (pstat);
119182b75dfdSjtc }
11926f885de1Sgwr #endif				/* SVR4 */
1193736ba086Slukem 
119482b75dfdSjtc /*
119582b75dfdSjtc ** New subsystem here. We allow the administrator to define
119682b75dfdSjtc ** up to NPRINTERDEFS aliases for printer names. This is done
119782b75dfdSjtc ** using the "/etc/pcnfsd.conf" file, which is read at startup.
119882b75dfdSjtc ** There are three entry points to this subsystem
119982b75dfdSjtc **
120082b75dfdSjtc ** void add_printer_alias(char *printer, char *alias_for, char *command)
120182b75dfdSjtc **
120282b75dfdSjtc ** This is invoked from "config_from_file()" for each
120382b75dfdSjtc ** "printer" line. "printer" is the name of a printer; note that
120482b75dfdSjtc ** it is possible to redefine an existing printer. "alias_for"
120582b75dfdSjtc ** is the name of the underlying printer, used for queue listing
120682b75dfdSjtc ** and other control functions. If it is "-", there is no
120782b75dfdSjtc ** underlying printer, or the administrative functions are
120882b75dfdSjtc ** not applicable to this printer. "command"
120982b75dfdSjtc ** is the command which should be run (via "su_popen()") if a
121082b75dfdSjtc ** job is printed on this printer. The following tokens may be
121182b75dfdSjtc ** embedded in the command, and are substituted as follows:
121282b75dfdSjtc **
121382b75dfdSjtc ** $FILE	-	path to the file containing the print data
121482b75dfdSjtc ** $USER	-	login of user
121582b75dfdSjtc ** $HOST	-	hostname from which job originated
121682b75dfdSjtc **
121782b75dfdSjtc ** Tokens may occur multiple times. If The command includes no
121882b75dfdSjtc ** $FILE token, the string " $FILE" is silently appended.
121982b75dfdSjtc **
122082b75dfdSjtc ** pr_list list_virtual_printers()
122182b75dfdSjtc **
122282b75dfdSjtc ** This is invoked from build_pr_list to generate a list of aliased
122382b75dfdSjtc ** printers, so that the client that asks for a list of valid printers
122482b75dfdSjtc ** will see these ones.
122582b75dfdSjtc **
122682b75dfdSjtc ** char *map_printer_name(char *printer)
122782b75dfdSjtc **
122882b75dfdSjtc ** If "printer" identifies an aliased printer, this function returns
122982b75dfdSjtc ** the "alias_for" name, or NULL if the "alias_for" was given as "-".
123082b75dfdSjtc ** Otherwise it returns its argument.
123182b75dfdSjtc **
123282b75dfdSjtc ** char *expand_alias(char *printer, char *file, char *user, char *host)
123382b75dfdSjtc **
123482b75dfdSjtc ** If "printer" is an aliased printer, this function returns a
123582b75dfdSjtc ** pointer to a static string in which the corresponding command
123682b75dfdSjtc ** has been expanded. Otherwise ot returns NULL.
123782b75dfdSjtc */
123882b75dfdSjtc #define NPRINTERDEFS	16
123982b75dfdSjtc int     num_aliases = 0;
124082b75dfdSjtc struct {
124182b75dfdSjtc 	char   *a_printer;
124282b75dfdSjtc 	char   *a_alias_for;
124382b75dfdSjtc 	char   *a_command;
124482b75dfdSjtc }       alias[NPRINTERDEFS];
124582b75dfdSjtc 
124682b75dfdSjtc void
124782b75dfdSjtc add_printer_alias(printer, alias_for, command)
124882b75dfdSjtc 	char   *printer;
124982b75dfdSjtc 	char   *alias_for;
125082b75dfdSjtc 	char   *command;
125182b75dfdSjtc {
12525d573dd9Sitojun 	size_t l;
12535d573dd9Sitojun 
125482b75dfdSjtc 	if (num_aliases < NPRINTERDEFS) {
125582b75dfdSjtc 		alias[num_aliases].a_printer = strdup(printer);
125682b75dfdSjtc 		alias[num_aliases].a_alias_for =
125782b75dfdSjtc 		    (strcmp(alias_for, "-") ? strdup(alias_for) : NULL);
125882b75dfdSjtc 		if (strstr(command, "$FILE"))
125982b75dfdSjtc 			alias[num_aliases].a_command = strdup(command);
126082b75dfdSjtc 		else {
12615d573dd9Sitojun 			l = strlen(command) + 8;
12625d573dd9Sitojun 			alias[num_aliases].a_command = (char *) grab(l);
12635d573dd9Sitojun 			strlcpy(alias[num_aliases].a_command, command, l);
12645d573dd9Sitojun 			strlcat(alias[num_aliases].a_command, " $FILE", l);
126582b75dfdSjtc 		}
126682b75dfdSjtc 		num_aliases++;
126782b75dfdSjtc 	}
126882b75dfdSjtc }
126982b75dfdSjtc 
1270736ba086Slukem pr_list
1271736ba086Slukem list_virtual_printers()
127282b75dfdSjtc {
127382b75dfdSjtc 	pr_list first = NULL;
127482b75dfdSjtc 	pr_list last = NULL;
127582b75dfdSjtc 	pr_list curr = NULL;
127682b75dfdSjtc 	int     i;
127782b75dfdSjtc 
127882b75dfdSjtc 
127982b75dfdSjtc 	if (num_aliases == 0)
128082b75dfdSjtc 		return (NULL);
128182b75dfdSjtc 
128282b75dfdSjtc 	for (i = 0; i < num_aliases; i++) {
128382b75dfdSjtc 		curr = (struct pr_list_item *)
128482b75dfdSjtc 		    grab(sizeof(struct pr_list_item));
128582b75dfdSjtc 
128682b75dfdSjtc 		curr->pn = strdup(alias[i].a_printer);
128782b75dfdSjtc 		if (alias[i].a_alias_for == NULL)
128882b75dfdSjtc 			curr->device = strdup("");
128982b75dfdSjtc 		else
129082b75dfdSjtc 			curr->device = strdup(alias[i].a_alias_for);
129182b75dfdSjtc 		curr->remhost = strdup("");
129282b75dfdSjtc 		curr->cm = strdup("(alias)");
129382b75dfdSjtc 		curr->pr_next = NULL;
129482b75dfdSjtc 		if (last == NULL)
129582b75dfdSjtc 			first = curr;
129682b75dfdSjtc 		else
129782b75dfdSjtc 			last->pr_next = curr;
129882b75dfdSjtc 		last = curr;
129982b75dfdSjtc 
130082b75dfdSjtc 	}
130182b75dfdSjtc 	return (first);
130282b75dfdSjtc }
130382b75dfdSjtc 
130482b75dfdSjtc 
130582b75dfdSjtc char   *
130682b75dfdSjtc map_printer_name(printer)
130782b75dfdSjtc 	char   *printer;
130882b75dfdSjtc {
130982b75dfdSjtc 	int     i;
131082b75dfdSjtc 	for (i = 0; i < num_aliases; i++) {
131182b75dfdSjtc 		if (!strcmp(printer, alias[i].a_printer))
131282b75dfdSjtc 			return (alias[i].a_alias_for);
131382b75dfdSjtc 	}
131482b75dfdSjtc 	return (printer);
131582b75dfdSjtc }
131682b75dfdSjtc 
1317736ba086Slukem void
131882b75dfdSjtc substitute(string, token, data)
131982b75dfdSjtc 	char   *string;
1320*0466bbb6Slukem 	const char   *token;
1321*0466bbb6Slukem 	const char   *data;
132282b75dfdSjtc {
132382b75dfdSjtc 	char    temp[512];
132482b75dfdSjtc 	char   *c;
132582b75dfdSjtc 
1326736ba086Slukem 	while ((c = strstr(string, token)) != NULL) {
132782b75dfdSjtc 		*c = '\0';
13285d573dd9Sitojun 		strlcpy(temp, string, sizeof(temp));
13295d573dd9Sitojun 		strlcat(temp, data, sizeof(temp));
133082b75dfdSjtc 		c += strlen(token);
13315d573dd9Sitojun 		strlcat(temp, c, sizeof(temp));
133282b75dfdSjtc 		strcpy(string, temp);
133382b75dfdSjtc 	}
133482b75dfdSjtc }
133582b75dfdSjtc 
133682b75dfdSjtc char   *
133782b75dfdSjtc expand_alias(printer, file, user, host)
133882b75dfdSjtc 	char   *printer;
133982b75dfdSjtc 	char   *file;
134082b75dfdSjtc 	char   *user;
134182b75dfdSjtc 	char   *host;
134282b75dfdSjtc {
134382b75dfdSjtc 	static char expansion[512];
134482b75dfdSjtc 	int     i;
134582b75dfdSjtc 	for (i = 0; i < num_aliases; i++) {
134682b75dfdSjtc 		if (!strcmp(printer, alias[i].a_printer)) {
13475d573dd9Sitojun 			strlcpy(expansion, alias[i].a_command,
13485d573dd9Sitojun 			    sizeof(expansion));
134982b75dfdSjtc 			substitute(expansion, "$FILE", file);
135082b75dfdSjtc 			substitute(expansion, "$USER", user);
135182b75dfdSjtc 			substitute(expansion, "$HOST", host);
135282b75dfdSjtc 			return (expansion);
135382b75dfdSjtc 		}
135482b75dfdSjtc 	}
135582b75dfdSjtc 	return (NULL);
135682b75dfdSjtc }
1357