pcnfsd_print.c revision 1.2 1 /* $NetBSD: pcnfsd_print.c,v 1.2 1995/07/25 22:20:48 gwr Exp $ */
2
3 /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_print.c 1.7 92/01/24 19:58:58 SMI */
4 /*
5 **=====================================================================
6 ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
7 ** @(#)pcnfsd_print.c 1.7 1/24/92
8 **=====================================================================
9 */
10 #include "common.h"
11 /*
12 **=====================================================================
13 ** I N C L U D E F I L E S E C T I O N *
14 ** *
15 ** If your port requires different include files, add a suitable *
16 ** #define in the customization section, and make the inclusion or *
17 ** exclusion of the files conditional on this. *
18 **=====================================================================
19 */
20 #include "pcnfsd.h"
21 #include <malloc.h>
22 #include <stdio.h>
23 #include <pwd.h>
24 #include <sys/file.h>
25 #include <signal.h>
26 #include <sys/stat.h>
27 #include <sys/ioctl.h>
28 #include <netdb.h>
29 #include <errno.h>
30 #include <string.h>
31
32 #ifndef SYSV
33 #include <sys/wait.h>
34 #endif
35
36 #ifdef ISC_2_0
37 #include <sys/fcntl.h>
38 #endif
39
40 #ifdef SHADOW_SUPPORT
41 #include <shadow.h>
42 #endif
43
44 /*
45 **---------------------------------------------------------------------
46 ** Other #define's
47 **---------------------------------------------------------------------
48 */
49 #ifndef MAXPATHLEN
50 #define MAXPATHLEN 1024
51 #endif
52
53 #ifndef SPOOLDIR
54 #define SPOOLDIR "/export/pcnfs"
55 #endif
56
57 #ifndef LPRDIR
58 #define LPRDIR "/usr/bin"
59 #endif
60
61 #ifndef LPCDIR
62 #define LPCDIR "/usr/sbin"
63 #endif
64
65 /*
66 ** The following defintions give the maximum time allowed for
67 ** an external command to run (in seconds)
68 */
69 #define MAXTIME_FOR_PRINT 10
70 #define MAXTIME_FOR_QUEUE 10
71 #define MAXTIME_FOR_CANCEL 10
72 #define MAXTIME_FOR_STATUS 10
73
74 #define QMAX 50
75
76 /*
77 ** The following is derived from ucb/lpd/displayq.c
78 */
79 #define SIZECOL 62
80 #define FILECOL 24
81
82 extern void scramble();
83 extern void run_ps630();
84 extern char *crypt();
85 extern FILE *su_popen();
86 extern int su_pclose();
87 int build_pr_list();
88 char *map_printer_name();
89 char *expand_alias();
90 void *grab();
91 void free_pr_list_item();
92 void free_pr_queue_item();
93 pr_list list_virtual_printers();
94
95 /*
96 **---------------------------------------------------------------------
97 ** Misc. variable definitions
98 **---------------------------------------------------------------------
99 */
100
101 extern int errno;
102 extern int interrupted; /* in pcnfsd_misc.c */
103 struct stat statbuf;
104 char pathname[MAXPATHLEN];
105 char new_pathname[MAXPATHLEN];
106 char sp_name[MAXPATHLEN] = SPOOLDIR;
107 char tempstr[256];
108 char delims[] = " \t\r\n:()";
109
110 pr_list printers = NULL;
111 pr_queue queue = NULL;
112
113 /*
114 **=====================================================================
115 ** C O D E S E C T I O N *
116 **=====================================================================
117 */
118
119 /*
120 * This is the latest word on the security check. The following
121 * routine "suspicious()" returns non-zero if the character string
122 * passed to it contains any shell metacharacters.
123 * Callers will typically code
124 *
125 * if(suspicious(some_parameter)) reject();
126 */
127
128 int suspicious (s)
129 char *s;
130 {
131 if(strpbrk(pathname, ";|&<>`'#!?*()[]^") != NULL)
132 return 1;
133 return 0;
134 }
135
136
137 int
138 valid_pr(pr)
139 char *pr;
140 {
141 char *p;
142 pr_list curr;
143 if(printers == NULL)
144 build_pr_list();
145
146 if(printers == NULL)
147 return(1); /* can't tell - assume it's good */
148
149 p = map_printer_name(pr);
150 if (p == NULL)
151 return(1); /* must be ok is maps to NULL! */
152 curr = printers;
153 while(curr) {
154 if(!strcmp(p, curr->pn))
155 return(1);
156 curr = curr->pr_next;
157 }
158
159 return(0);
160 }
161
162 pirstat pr_init(sys, pr, sp)
163 char *sys;
164 char *pr;
165 char**sp;
166 {
167 int dir_mode = 0777;
168 int rc;
169
170 *sp = &pathname[0];
171 pathname[0] = '\0';
172
173 if(suspicious(sys) || suspicious(pr))
174 return(PI_RES_FAIL);
175
176 /* get pathname of current directory and return to client */
177
178 (void)sprintf(pathname,"%s/%s",sp_name, sys);
179 (void)mkdir(sp_name, dir_mode); /* ignore the return code */
180 (void)chmod(sp_name, dir_mode);
181 rc = mkdir(pathname, dir_mode); /* DON'T ignore this return code */
182 if((rc < 0 && errno != EEXIST) ||
183 (chmod(pathname, dir_mode) != 0) ||
184 (stat(pathname, &statbuf) != 0) ||
185 !(statbuf.st_mode & S_IFDIR)) {
186 (void)sprintf(tempstr,
187 "rpc.pcnfsd: unable to set up spool directory %s\n",
188 pathname);
189 msg_out(tempstr);
190 pathname[0] = '\0'; /* null to tell client bad vibes */
191 return(PI_RES_FAIL);
192 }
193 if (!valid_pr(pr))
194 {
195 pathname[0] = '\0'; /* null to tell client bad vibes */
196 return(PI_RES_NO_SUCH_PRINTER);
197 }
198 return(PI_RES_OK);
199
200 }
201
202
204 psrstat pr_start2(system, pr, user, fname, opts, id)
205 char *system;
206 char *pr;
207 char *user;
208 char *fname;
209 char *opts;
210 char **id;
211 {
212 char snum[20];
213 static char req_id[256];
214 char cmdbuf[256];
215 char resbuf[256];
216 FILE *fd;
217 int i;
218 char *xcmd;
219 char *cp;
220 int failed = 0;
221
222 #ifdef HACK_FOR_ROTATED_TRANSCRIPT
223 char scratch[512];
224 #endif
225
226
227 if(suspicious(system) ||
228 suspicious(pr) ||
229 suspicious(user) ||
230 suspicious(fname))
231 return(PS_RES_FAIL);
232
233 (void)sprintf(pathname,"%s/%s/%s",sp_name,
234 system,
235 fname);
236
237 *id = &req_id[0];
238 req_id[0] = '\0';
239
240 if (stat(pathname, &statbuf))
241 {
242 /*
243 **-----------------------------------------------------------------
244 ** We can't stat the file. Let's try appending '.spl' and
245 ** see if it's already in progress.
246 **-----------------------------------------------------------------
247 */
248
249 (void)strcat(pathname, ".spl");
250 if (stat(pathname, &statbuf))
251 {
252 /*
253 **----------------------------------------------------------------
254 ** It really doesn't exist.
255 **----------------------------------------------------------------
256 */
257
258
259 return(PS_RES_NO_FILE);
260 }
261 /*
262 **-------------------------------------------------------------
263 ** It is already on the way.
264 **-------------------------------------------------------------
265 */
266
267
268 return(PS_RES_ALREADY);
269 }
270
271 if (statbuf.st_size == 0)
272 {
273 /*
274 **-------------------------------------------------------------
275 ** Null file - don't print it, just kill it.
276 **-------------------------------------------------------------
277 */
278 (void)unlink(pathname);
279
280 return(PS_RES_NULL);
281 }
282 /*
283 **-------------------------------------------------------------
284 ** The file is real, has some data, and is not already going out.
285 ** We rename it by appending '.spl' and exec "lpr" to do the
286 ** actual work.
287 **-------------------------------------------------------------
288 */
289 (void)strcpy(new_pathname, pathname);
290 (void)strcat(new_pathname, ".spl");
291
292 /*
293 **-------------------------------------------------------------
294 ** See if the new filename exists so as not to overwrite it.
295 **-------------------------------------------------------------
296 */
297
298
299 if (!stat(new_pathname, &statbuf))
300 {
301 (void)strcpy(new_pathname, pathname); /* rebuild a new name */
302 (void)sprintf(snum, "%d", rand()); /* get some number */
303 (void)strncat(new_pathname, snum, 3);
304 (void)strcat(new_pathname, ".spl"); /* new spool file */
305 }
306 if (rename(pathname, new_pathname))
307 {
308 /*
309 **---------------------------------------------------------------
310 ** Should never happen.
311 **---------------------------------------------------------------
312 */
313 (void)sprintf(tempstr, "rpc.pcnfsd: spool file rename (%s->%s) failed.\n",
314 pathname, new_pathname);
315 msg_out(tempstr);
316 return(PS_RES_FAIL);
317 }
318
319 if (*opts == 'd')
320 {
321 /*
322 **------------------------------------------------------
323 ** This is a Diablo print stream. Apply the ps630
324 ** filter with the appropriate arguments.
325 **------------------------------------------------------
326 */
327 (void)run_ps630(new_pathname, opts);
328 }
329 /*
330 ** Try to match to an aliased printer
331 */
332 xcmd = expand_alias(pr, new_pathname, user, system);
333 /*
334 **----------------------------------------------------------
335 ** Use the copy option so we can remove the orignal spooled
336 ** nfs file from the spool directory.
337 **----------------------------------------------------------
338 */
339 if(!xcmd) {
340 sprintf(cmdbuf, "%s/lpr -P%s %s",
341 LPRDIR, pr, new_pathname);
342 xcmd = cmdbuf;
343 }
344 if ((fd = su_popen(user, xcmd, MAXTIME_FOR_PRINT)) == NULL) {
345 msg_out("rpc.pcnfsd: su_popen failed");
346 return(PS_RES_FAIL);
347 }
348 req_id[0] = '\0'; /* asume failure */
349 while(fgets(resbuf, 255, fd) != NULL) {
350 i = strlen(resbuf);
351 if(i)
352 resbuf[i-1] = '\0'; /* trim NL */
353 if(!strncmp(resbuf, "request id is ", 14))
354 /* New - just the first word is needed */
355 strcpy(req_id, strtok(&resbuf[14], delims));
356 else if (strembedded("disabled", resbuf))
357 failed = 1;
358 }
359 if(su_pclose(fd) == 255)
360 msg_out("rpc.pcnfsd: su_pclose alert");
361 (void)unlink(new_pathname);
362 return((failed | interrupted)? PS_RES_FAIL : PS_RES_OK);
363 }
364
365
367 /*
368 * determine which printers are valid...
369 * on BSD use "lpc status"
370 * on SVR4 use "lpstat -v"
371 */
372 int
373 build_pr_list()
374 {
375 pr_list last = NULL;
376 pr_list curr = NULL;
377 char buff[256];
378 FILE *p;
379 char *cp;
380 int saw_system;
381
382 sprintf(buff, "%s/lpc status", LPCDIR);
383 p = popen(buff, "r");
384 if(p == NULL) {
385 msg_out("rpc.pcnfsd: unable to popen lpc stat");
386 return(0);
387 }
388
389 while(fgets(buff, 255, p) != NULL) {
390 if (isspace(buff[0]))
391 continue;
392
393 if ((cp = strtok(buff, delims)) == NULL)
394 continue;
395
396 curr = (struct pr_list_item *)
397 grab(sizeof (struct pr_list_item));
398
399 /* XXX - Should distinguish remote printers. */
400 curr->pn = strdup(cp);
401 curr->device = strdup(cp);
402 curr->remhost = strdup("");
403 curr->cm = strdup("-");
404 curr->pr_next = NULL;
405
406 if(last == NULL)
407 printers = curr;
408 else
409 last->pr_next = curr;
410 last = curr;
411
412 }
413 (void) fclose(p);
414
415 /*
416 ** Now add on the virtual printers, if any
417 */
418 if(last == NULL)
419 printers = list_virtual_printers();
420 else
421 last->pr_next = list_virtual_printers();
422
423 return(1);
424 }
425
426 void *grab(n)
427 int n;
428 {
429 void *p;
430
431 p = (void *)malloc(n);
432 if(p == NULL) {
433 msg_out("rpc.pcnfsd: malloc failure");
434 exit(1);
435 }
436 return(p);
437 }
438
439 void
440 free_pr_list_item(curr)
441 pr_list curr;
442 {
443 if(curr->pn)
444 free(curr->pn);
445 if(curr->device)
446 free(curr->device);
447 if(curr->remhost)
448 free(curr->remhost);
449 if(curr->cm)
450 free(curr->cm);
451 if(curr->pr_next)
452 free_pr_list_item(curr->pr_next); /* recurse */
453 free(curr);
454 }
455 /*
456 ** Print queue handling.
457 **
458 ** Note that the first thing we do is to discard any
459 ** existing queue.
460 */
461
462 pirstat
463 build_pr_queue(pn, user, just_mine, p_qlen, p_qshown)
464 printername pn;
465 username user;
466 int just_mine;
467 int *p_qlen;
468 int *p_qshown;
469 {
470 pr_queue last = NULL;
471 pr_queue curr = NULL;
472 char buff[256];
473 FILE *p;
474 char *cp;
475 int i;
476 char *rank;
477 char *owner;
478 char *job;
479 char *files;
480 char *totsize;
481
482 if(queue) {
483 free_pr_queue_item(queue);
484 queue = NULL;
485 }
486 *p_qlen = 0;
487 *p_qshown = 0;
488 pn = map_printer_name(pn);
489 if(pn == NULL || suspicious(pn))
490 return(PI_RES_NO_SUCH_PRINTER);
491
492 sprintf(buff, "%s/lpq -P%s", LPRDIR, pn);
493
494 p = su_popen(user, buff, MAXTIME_FOR_QUEUE);
495 if(p == NULL) {
496 msg_out("rpc.pcnfsd: unable to popen() lpq");
497 return(PI_RES_FAIL);
498 }
499
500 while(fgets(buff, 255, p) != NULL) {
501 i = strlen(buff) - 1;
502 buff[i] = '\0'; /* zap trailing NL */
503 if(i < SIZECOL)
504 continue;
505 if(!mystrncasecmp(buff, "rank", 4))
506 continue;
507
508 totsize = &buff[SIZECOL-1];
509 files = &buff[FILECOL-1];
510 cp = totsize;
511 cp--;
512 while(cp > files && isspace(*cp))
513 *cp-- = '\0';
514
515 buff[FILECOL-2] = '\0';
516
517 cp = strtok(buff, delims);
518 if(!cp)
519 continue;
520 rank = cp;
521
522 cp = strtok(NULL, delims);
523 if(!cp)
524 continue;
525 owner = cp;
526
527 cp = strtok(NULL, delims);
528 if(!cp)
529 continue;
530 job = cp;
531
532 *p_qlen += 1;
533
534 if(*p_qshown > QMAX)
535 continue;
536
537 if(just_mine && mystrcasecmp(owner, user))
538 continue;
539
540 *p_qshown += 1;
541
542 curr = (struct pr_queue_item *)
543 grab(sizeof (struct pr_queue_item));
544
545 curr->position = atoi(rank); /* active -> 0 */
546 curr->id = strdup(job);
547 curr->size = strdup(totsize);
548 curr->status = strdup(rank);
549 curr->system = strdup("");
550 curr->user = strdup(owner);
551 curr->file = strdup(files);
552 curr->cm = strdup("-");
553 curr->pr_next = NULL;
554
555 if(last == NULL)
556 queue = curr;
557 else
558 last->pr_next = curr;
559 last = curr;
560
561 }
562 (void) su_pclose(p);
563 return(PI_RES_OK);
564 }
565
566 void
567 free_pr_queue_item(curr)
568 pr_queue curr;
569 {
570 if(curr->id)
571 free(curr->id);
572 if(curr->size)
573 free(curr->size);
574 if(curr->status)
575 free(curr->status);
576 if(curr->system)
577 free(curr->system);
578 if(curr->user)
579 free(curr->user);
580 if(curr->file)
581 free(curr->file);
582 if(curr->cm)
583 free(curr->cm);
584 if(curr->pr_next)
585 free_pr_queue_item(curr->pr_next); /* recurse */
586 free(curr);
587 }
588
589
590
591 pirstat
592 get_pr_status(pn, avail, printing, qlen, needs_operator, status)
593 printername pn;
594 bool_t *avail;
595 bool_t *printing;
596 int *qlen;
597 bool_t *needs_operator;
598 char *status;
599 {
600 char cmd[128];
601 char buff[256];
602 char buff2[256];
603 char pname[64];
604 FILE *p;
605 char *cp;
606 char *cp1;
607 char *cp2;
608 int n;
609 pirstat stat = PI_RES_NO_SUCH_PRINTER;
610
611 /* assume the worst */
612 *avail = FALSE;
613 *printing = FALSE;
614 *needs_operator = FALSE;
615 *qlen = 0;
616 *status = '\0';
617
618 pn = map_printer_name(pn);
619 if(pn == NULL || suspicious(pn))
620 return(PI_RES_NO_SUCH_PRINTER);
621
622 sprintf(pname, "%s:", pn);
623 n = strlen(pname);
624
625 #if 0
626 /*
627 * We used to use lpstat -a, but it breaks because of
628 * printer alias inconsistency
629 */
630 p = popen("/usr/bin/lpstat -a", "r");
631 #else
632 /*
633 * So now we use: lpc status
634 */
635 sprintf(cmd, "%s/lpc status %s", LPCDIR, pn);
636 p = popen(cmd, "r");
637 #endif
638 if(p == NULL) {
639 msg_out("rpc.pcnfsd: unable to popen() lp status");
640 return(PI_RES_FAIL);
641 }
642
643 while(fgets(buff, 255, p) != NULL) {
644 if(strncmp(buff, pname, n))
645 continue;
646 /*
647 ** We have a match. The only failure now is PI_RES_FAIL if
648 ** lpstat output cannot be decoded
649 */
650 stat = PI_RES_FAIL;
651 /*
652 ** The next four lines are usually if the form
653 **
654 ** queuing is [enabled|disabled]
655 ** printing is [enabled|disabled]
656 ** [no entries | N entr[y|ies] in spool area]
657 ** <status message, may include the word "attention">
658 */
659 while(fgets(buff, 255, p) != NULL && isspace(buff[0])) {
660 cp = buff;
661 while(isspace(*cp))
662 cp++;
663 if(*cp == '\0')
664 break;
665 cp1 = cp;
666 cp2 = buff2;
667 while(*cp1 && *cp1 != '\n') {
668 *cp2++ = tolower(*cp1);
669 cp1++;
670 }
671 *cp1 = '\0';
672 *cp2 = '\0';
673 /*
674 ** Now buff2 has a lower-cased copy and cp points at the original;
675 ** both are null terminated without any newline
676 */
677 if(!strncmp(buff2, "queuing", 7)) {
678 *avail = (strstr(buff2, "enabled") != NULL);
679 continue;
680 }
681 if(!strncmp(buff2, "printing", 8)) {
682 *printing = (strstr(buff2, "enabled") != NULL);
683 continue;
684 }
685 if(isdigit(buff2[0]) && (strstr(buff2, "entr") !=NULL)) {
686
687 *qlen = atoi(buff2);
688 continue;
689 }
690 if(strstr(buff2, "attention") != NULL ||
691 strstr(buff2, "error") != NULL)
692 *needs_operator = TRUE;
693 if(*needs_operator || strstr(buff2, "waiting") != NULL)
694 strcpy(status, cp);
695 }
696 stat = PI_RES_OK;
697 break;
698 }
699 (void) pclose(p);
700 return(stat);
701 }
702
703
704 pcrstat pr_cancel(pr, user, id)
705 char *pr;
706 char *user;
707 char *id;
708 {
709 char cmdbuf[256];
710 char resbuf[256];
711 FILE *fd;
712 int i;
713 pcrstat stat = PC_RES_NO_SUCH_JOB;
714
715 pr = map_printer_name(pr);
716 if(pr == NULL || suspicious(pr))
717 return(PC_RES_NO_SUCH_PRINTER);
718 if(suspicious(id))
719 return(PC_RES_NO_SUCH_JOB);
720
721 sprintf(cmdbuf, "%s/lprm -P%s %s", LPRDIR, pr, id);
722 if ((fd = su_popen(user, cmdbuf, MAXTIME_FOR_CANCEL)) == NULL) {
723 msg_out("rpc.pcnfsd: su_popen failed");
724 return(PC_RES_FAIL);
725 }
726 while(fgets(resbuf, 255, fd) != NULL) {
727 i = strlen(resbuf);
728 if(i)
729 resbuf[i-1] = '\0'; /* trim NL */
730 if(strstr(resbuf, "dequeued") != NULL)
731 stat = PC_RES_OK;
732 if(strstr(resbuf, "unknown printer") != NULL)
733 stat = PC_RES_NO_SUCH_PRINTER;
734 if(strstr(resbuf, "Permission denied") != NULL)
735 stat = PC_RES_NOT_OWNER;
736 }
737 if(su_pclose(fd) == 255)
738 msg_out("rpc.pcnfsd: su_pclose alert");
739 return(stat);
740 }
741
742
743 /*
745 ** New subsystem here. We allow the administrator to define
746 ** up to NPRINTERDEFS aliases for printer names. This is done
747 ** using the "/etc/pcnfsd.conf" file, which is read at startup.
748 ** There are three entry points to this subsystem
749 **
750 ** void add_printer_alias(char *printer, char *alias_for, char *command)
751 **
752 ** This is invoked from "config_from_file()" for each
753 ** "printer" line. "printer" is the name of a printer; note that
754 ** it is possible to redefine an existing printer. "alias_for"
755 ** is the name of the underlying printer, used for queue listing
756 ** and other control functions. If it is "-", there is no
757 ** underlying printer, or the administrative functions are
758 ** not applicable to this printer. "command"
759 ** is the command which should be run (via "su_popen()") if a
760 ** job is printed on this printer. The following tokens may be
761 ** embedded in the command, and are substituted as follows:
762 **
763 ** $FILE - path to the file containing the print data
764 ** $USER - login of user
765 ** $HOST - hostname from which job originated
766 **
767 ** Tokens may occur multiple times. If The command includes no
768 ** $FILE token, the string " $FILE" is silently appended.
769 **
770 ** pr_list list_virtual_printers()
771 **
772 ** This is invoked from build_pr_list to generate a list of aliased
773 ** printers, so that the client that asks for a list of valid printers
774 ** will see these ones.
775 **
776 ** char *map_printer_name(char *printer)
777 **
778 ** If "printer" identifies an aliased printer, this function returns
779 ** the "alias_for" name, or NULL if the "alias_for" was given as "-".
780 ** Otherwise it returns its argument.
781 **
782 ** char *expand_alias(char *printer, char *file, char *user, char *host)
783 **
784 ** If "printer" is an aliased printer, this function returns a
785 ** pointer to a static string in which the corresponding command
786 ** has been expanded. Otherwise ot returns NULL.
787 */
788 #define NPRINTERDEFS 16
789 int num_aliases = 0;
790 struct {
791 char *a_printer;
792 char *a_alias_for;
793 char *a_command;
794 } alias [NPRINTERDEFS];
795
796
797
798 void
799 add_printer_alias(printer, alias_for, command)
800 char *printer;
801 char *alias_for;
802 char *command;
803 {
804 if(num_aliases < NPRINTERDEFS) {
805 alias[num_aliases].a_printer = strdup(printer);
806 alias[num_aliases].a_alias_for =
807 (strcmp(alias_for, "-") ? strdup(alias_for) : NULL);
808 if(strstr(command, "$FILE"))
809 alias[num_aliases].a_command = strdup(command);
810 else {
811 alias[num_aliases].a_command = (char *)grab(strlen(command) + 8);
812 strcpy(alias[num_aliases].a_command, command);
813 strcat(alias[num_aliases].a_command, " $FILE");
814 }
815 num_aliases++;
816 }
817 }
818
819 pr_list list_virtual_printers()
820 {
821 pr_list first = NULL;
822 pr_list last = NULL;
823 pr_list curr = NULL;
824 int i;
825
826
827 if(num_aliases == 0)
828 return(NULL);
829
830 for (i = 0; i < num_aliases; i++) {
831 curr = (struct pr_list_item *)
832 grab(sizeof (struct pr_list_item));
833
834 curr->pn = strdup(alias[i].a_printer);
835 if(alias[i].a_alias_for == NULL)
836 curr->device = strdup("");
837 else
838 curr->device = strdup(alias[i].a_alias_for);
839 curr->remhost = strdup("");
840 curr->cm = strdup("(alias)");
841 curr->pr_next = NULL;
842 if(last == NULL)
843 first = curr;
844 else
845 last->pr_next = curr;
846 last = curr;
847
848 }
849 return(first);
850 }
851
852
853 char *
854 map_printer_name(printer)
855 char *printer;
856 {
857 int i;
858 for (i = 0; i < num_aliases; i++){
859 if(!strcmp(printer, alias[i].a_printer))
860 return(alias[i].a_alias_for);
861 }
862 return(printer);
863 }
864
865 static void
866 substitute(string, token, data)
867 char *string;
868 char *token;
869 char *data;
870 {
871 char temp[512];
872 char *c;
873
874 while(c = strstr(string, token)) {
875 *c = '\0';
876 strcpy(temp, string);
877 strcat(temp, data);
878 c += strlen(token);
879 strcat(temp, c);
880 strcpy(string, temp);
881 }
882 }
883
884 char *
885 expand_alias(printer, file, user, host)
886 char *printer;
887 char *file;
888 char *user;
889 char *host;
890 {
891 static char expansion[512];
892 int i;
893 for (i = 0; i < num_aliases; i++){
894 if(!strcmp(printer, alias[i].a_printer)) {
895 strcpy(expansion, alias[i].a_command);
896 substitute(expansion, "$FILE", file);
897 substitute(expansion, "$USER", user);
898 substitute(expansion, "$HOST", host);
899 return(expansion);
900 }
901 }
902 return(NULL);
903 }
904
905