pc-pap An intelligent Appletalk (CAP) print filter
David J. Hughes
bambi at kirk.nmg.bu.oz.au
Thu Feb 14 15:26:50 AEST 1991
An extract from the README file :-
This program is a replacement PAP based lpd input filter for
the standard CAP papif. At the simplest level, it performs
the same function as papif (send a printjob to an appletalk
based laserwriter). It also provides for definable language
recognition and filtering based on the contents of the first
line of the print job (such as a PostScript magic or #! /bin/sh
in shell scripts). It also splits PostScript printjobs into
individual PAP connections. This is essential if IBM PC
based applications, such as MS-Word, print via this queue.
As most PostScript PC print jobs consist of a procedure set
followed by a document, the print job sent to the laser
contains a ^D in the middle. An Apple Laser will see this
and flush the job untill end of file. Unfortunately, if the
laser is connected to appletalk, it assumes that end of file is
when the PAP connection is dropped. This is why each
PostScript print job is split into it's own PAP connection.
What follows is a shar file containing the source to pc-pap, a README
file and a sample configuration. It has been tested under Ultrix 3.1
and 4.1 and SunOS 4.1. If you port it to any other system/OS
combination please let me know.
Please send comments and bug reports to my address listed below.
+----------------------------------------------------------------------------+
| David J. Hughes (AKA bambi) | bambi at kirk.bu.oz.au |
| Systems Programmer | bambi at kirk.bu.oz.au@uunet.uu.net |
| Comms Development & Operations | ..!uunet!munnari!kirk.bu.oz.au!bambi |
| Bond University, Gold Coast | Phone : +61 75 951111 |
| Queensland, Australia 4229 | Fax : +61 75 951456 |
+----------------------------------------------------------------------------+
--------------------------------- CUT HERE --------------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
# wrapped by bambi at kirk.bu.oz.au
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\End\Of\Shar\'
#CFLAGS= -DDEBUG -g -c
CFLAGS= -O -c
OBJS= pc-pap.o config.o
.c.o:
cc $(CFLAGS) $*.c
all: pc-pap
clean:
rm *.o pc-pap
pc-pap.o : pc-pap.c Makefile
config.o : config.c Makefile
pc-pap : pc-pap.o config.o
cc -o pc-pap $(OBJS) -lcap
install:
cp pc-pap /usr/local/lib/lpdfilters
chmod 760 /usr/local/lib/lpdfilters/pc-pap
\End\Of\Shar\
else
echo "will not over write ./Makefile"
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\End\Of\Shar\'
# @(#)README (Bond) bambi
Title : PC-PAP.c
Author : David J. Hughes bambi at kirk.bu.oz.au
Date : 27-Jan-1991
Dept : Communications Development and Operations
Bond University
This program is a replacement PAP based lpd input filter for
the standard CAP papif. At the simplest level, it performs
the same function as papif (send a printjob to an appletalk
based laserwriter). It also provides for definable language
recognition and filtering based on the contents of the first
line of the print job (such as a PostScript magic or #! /bin/sh
in shell scripts). It also splits PostScript printjobs into
individual PAP connections. This is essential if IBM PC
based applications, such as MS-Word, print via this queue.
As most PostScript PC print jobs consist of a procedure set
followed by a document, the print job sent to the laser
contains a ^D in the middle. An Apple Laser will see this
and flush the job untill end of file. Unfortunately, if the
laser is connected to appletalk, it assumes that end of file is
when the PAP connection is dropped. This is why each
PostScript print job is split into it's own PAP connection.
To configure the language recognition features edit the
pc-pap.conf file to represent your local site. Details of the
file format are outlined in the pc-pap.conf.example file. When
the configuration file is completed, it shoulod be installed as
/usr/local/lib/pc-pap.conf. To check the configuration file,
run pc-pap from the commandline. The first task it performs is
to parse and load the configuration from file. Any errors found
will be reported to the terminal (including location and type
of error).
Installation of the pc-pap filter is the same as the
installation of papif. Basically, the software uses the program
name (argv[0]) as the name of the printer to which the data
should be sent. To install the filter for a printer called
admin-laser, create a sym-link to pc-pap called admin-laser.
Set the if= field in the /etc/printcap file to point to the
sym-link as the printers input filter.
The only other file that is used by pc-pap is the
/etc/cap.printers file. It expects it to be in the same format
as is specified in the CAP 5.0 distribution.
Testing of the filter can be performed by redirecting an input
file into the sym-link (eg. admin-laser < test.ps). If an error
is encountered, it will be logged via syslog.
\End\Of\Shar\
else
echo "will not over write ./README"
fi
if `test ! -s ./config.c`
then
echo "writing ./config.c"
cat > ./config.c << '\End\Of\Shar\'
/*
* Title : config.c
* Author : David J. Hughes bambi at kirk.bu.oz.au
* Date : 27-Jan-1991
* Dept : Communications Development and Operations
* Bond University
*
* Routines to parse and load the configuration file
*/
#include <stdio.h>
#include <syslog.h>
#include <strings.h>
#include <malloc.h>
#include "pc-pap.h"
char *ps_token[10]; /* List of tokens */
token_t *magics[50];
filter_t *filters[10];
int magic_offset = 0,
ps_offset = 0,
filter_offset = 0,
ps_found = 0,
text_found = 0;
/*
** SUBST_ASCII : Check the string for any embedded ASCII values and
** convert them to there actual character codes.
**
*/
char * subst_ascii(str)
char *str;
{
static char ret_str[80];
char *cp1,
*cp2,
ascii[4];
strcpy(ret_str,"");
cp1 = str;
cp2 = ret_str;
while(*cp1 != NULL)
{
if(*cp1 != '\\')
*cp2 = *cp1;
else
{
ascii[0] = *++cp1;
ascii[1] = *++cp1;
ascii[2] = *++cp1;
ascii[3] = 0;
*cp2 = (char) atoi(ascii);
}
cp1++;
cp2++;
}
*cp2 = 0;
return(ret_str);
}
/*
** BAD_CONFIG : Report configuration error.
**
*/
bad_config(line,error)
int line;
char *error;
{
fprintf(stderr,"\n\nPC-PAP : Error in configuration file at line %d.",
line);
if (error != NULL)
fprintf(stderr,"\n %s.\n",error);
fprintf(stderr,"\nExiting \007\n");
syslog(LOG_DEBUG,"PC-PAP : Error in config at line %d",line);
exit(1);
}
/*
** READ_PS : load the PostScript magic tokens
**
*/
read_ps(line,line_num)
char *line;
int line_num;
{
char *token,
*store;
if (index(line,':') == NULL)
bad_config(line_num,"No terminator on PostScript magic token");
token = strtok(line,":");
if (token == NULL)
bad_config(line_num,"No token defined");
store = (char *) malloc(strlen(token)+1);
strcpy(store,subst_ascii(token));
ps_token[ps_offset++] = store;
ps_found = 1;
}
/*
** STORE_FILTER : Write a set filter definition into the filter vector.
**
*/
store_filter(lang,line,line_num)
char *lang,
*line;
int line_num;
{
char *token,
error_msg[80];
filter_t *tmp_filter;
int token_count = 0,
arg_num = 0;
tmp_filter = (filter_t *) malloc(sizeof(filter_t));
if(strlen(lang) >= lang_len)
{
free(tmp_filter);
sprintf(error_msg,"Language id too long. Max is %d characters",
lang_len);
bad_config(line_num,error_msg);
}
strcpy(tmp_filter->lang,subst_ascii(lang));
if((token = strtok(line,":")) == NULL)
{
free(tmp_filter);
bad_config(line_num,"Bad filter definition (2nd Token)");
}
if(strlen(token) >= path_len)
{
free(tmp_filter);
sprintf(error_msg,"Filter path too long. Max is %d characters",
path_len);
bad_config(line_num,error_msg);
}
strcpy(tmp_filter->path,subst_ascii(token));
if((token = strtok(NULL,":")) == NULL)
{
free(tmp_filter);
bad_config(line_num,"Bad text filter definition (3nd Token)");
}
if(strlen(token) >= name_len)
{
free(tmp_filter);
sprintf(error_msg,"Filter name too long. Max is %d characters",
name_len);
bad_config(line_num,error_msg);
}
strcpy(tmp_filter->name,subst_ascii(token));
while((token = strtok(NULL,":")) != NULL)
{
if(strlen(token) >= args_len)
{
free(tmp_filter);
sprintf(error_msg,
"Filter arguements too long. Max is %d characters",
args_len);
bad_config(line_num,error_msg);
}
strcpy(tmp_filter->args[arg_num++],subst_ascii(token));
}
while(arg_num < num_filter_args)
tmp_filter->args[arg_num++][0] = NULL;
filters[filter_offset++] = tmp_filter;
}
/*
** READ_TEXT : load the Text to PostScript filter details
**
*/
read_text(line, line_num)
char *line;
int line_num;
{
char *token;
store_filter(TEXT_PS,line,line_num);
text_found = 1;
}
/*
** READ_FILTERS : load the language filter definitions
**
*/
read_filters(line, line_num)
char *line;
int line_num;
{
char *lang,
*rest;
lang = strtok(line,":");
rest = strtok(NULL,"\n");
store_filter(lang,rest,line_num);
}
/*
** READ_MAGICS : load the magic tokens definitions
**
*/
read_magics(line,line_num)
char *line;
{
char *token,
error_msg[80];
token_t *tmp_token;
int token_count = 0;
tmp_token = (token_t *) malloc(sizeof(token_t));
if((token = strtok(line,":")) == NULL)
bad_config(line_num,"Missing tokens");
if(strlen(token) >= lang_len)
{
free(tmp_token);
sprintf(error_msg,"Language id too long. Max is %d characters",
lang_len);
bad_config(line_num,error_msg);
}
strcpy(tmp_token->lang,subst_ascii(token));
if((token = strtok(NULL,":")) != NULL)
{
if(strlen(token) >= magic_len)
{
free(tmp_token);
sprintf(error_msg,
"Magic token too long. Max is %d characters",
magic_len);
bad_config(line_num,error_msg);
}
strcpy(tmp_token->token, subst_ascii(token));
}
else
bad_config(line_num,"No magic string supplied.");
magics[magic_offset++] = tmp_token;
}
/*
** LOAD_CONFIG : load the configuration file into internal structures.
**
** Note : The internal stat machine has the following states :-
**
**
** 0. Starting config read
** 1. Reading PostScript section
** 2. Reading Text section
** 3. Reading Filters section
** 4. Reading Magics section
*/
load_config()
{
FILE *conf;
char conf_line[100],
conf_path[100],
*token;
int state = 0,
line_num=0;
sprintf(conf_path,"%s/%s",conf_dir,conf_file);
conf = fopen(conf_path,"r");
if (conf == NULL)
{
fprintf(stderr,"\007\nPC-PAP : Could not open configuration");
fprintf(stderr," file. Aborting.\n\n");
syslog(LOG_DEBUG,"PC-PAP : Could not open configuration file");
exit(1);
}
while (!feof(conf))
{
fgets(conf_line,99,conf);
conf_line[strlen(conf_line)-1] = 0;
line_num++;
if (!feof(conf))
{
switch(conf_line[0])
{
case '#': /* Comment */
case '\0': /* Blank Line */
break;
case ' ':
case '\t':
bad_config(line_num,
"Leading white space");
break;
case '+': /* State change */
token = strtok(conf_line+1," \n");
if (strcmp(token,"postscript") == 0)
state = 1;
else
if (strcmp(token,"text") == 0)
state = 2;
else
if (strcmp(token,"filters") == 0)
state = 3;
else
if (strcmp(token,"magics") == 0)
state = 4;
else
bad_config(line_num,
"Unknown section header");
break;
default:
switch(state)
{
case 0:
bad_config(line_num,
"Section not defined");
break;
case 1:
read_ps(conf_line,
line_num);
break;
case 2:
read_text(conf_line,
line_num);
break;
case 3:
read_filters(conf_line,
line_num);
break;
case 4:
read_magics(conf_line,
line_num);
break;
}
}
}
}
}
\End\Of\Shar\
else
echo "will not over write ./config.c"
fi
if `test ! -s ./pc-pap.c`
then
echo "writing ./pc-pap.c"
cat > ./pc-pap.c << '\End\Of\Shar\'
/*
* Title : PC-PAP.c
* Author : David J. Hughes bambi at kirk.bu.oz.au
* Date : 14-June-1990
* Dept : Communications Development and Operations
* Bond University
*
*--------------------------------------------------------------------------
* Edit history
*
* 14-June-1990 bambi
*
* Initial development
*--------------------------------------------------------------------------
* 27-Jan-1991 bambi
*
* Remove the hard-coded configuration for language recognition and
* use a config file to be read at run-time.
*
* Fix time-out error when Laser returns a PAP eof flag to us on a
* read.
*
* Include Job details in the lpq status file so that PC users can see the
* name and type of job being printed (only supported in certain
* applications such as Excel, PageMaker, Word for Windows etc.)
*
* Fix up the handling of printer error returns such as "Out of
* paper"
*--------------------------------------------------------------------------
*
*/
#include <stdio.h>
#include <syslog.h>
#include <varargs.h>
#include <strings.h>
#include <signal.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/file.h>
#include <netat/appletalk.h>
#include <netat/compat.h>
#include "pc-pap.h"
#define BUF_SIZ QUANTUM * PAPSegSize
/*
** Global variable definition section
*/
char printer[20],
username[20],
hostname[20],
acct_file[80],
*atalk_name,
r_buf[100]; /* PAPRead buffer */
int sock, /* Must be global for signal handler */
r_comp = 0, /* PAPRead completion flag */
r_len = 0, /* PAPRead data length */
r_err = 0,
r_eof = 0,
CURR_PROC = 0;
/*
** External variable definition section
*/
extern char *ps_token[];
extern token_t *magics[];
extern filter_t *filters[];
extern int magic_offset,
ps_offset,
filter_offset;
/**************************************************************************
* Close down the PAP Connection and exit REPRINT
*/
fatal(sig)
int sig;
{
char sig_name[15],
proc_name[15];
switch (sig)
{
case 1: strcpy(sig_name,"SIGHUP");
break;
case 2: strcpy(sig_name,"SIGINT");
break;
case 3: strcpy(sig_name,"SIGQUIT");
break;
case 4: strcpy(sig_name,"SIGILL");
break;
case 5: strcpy(sig_name,"SIGTRAP");
break;
case 6: strcpy(sig_name,"SIGIOT");
break;
case 7: strcpy(sig_name,"SIGEMT");
break;
case 8: strcpy(sig_name,"SIGFPE");
break;
case 9: strcpy(sig_name,"SIGKILL");
break;
case 10: strcpy(sig_name,"SIGBUS");
break;
case 11: strcpy(sig_name,"SIGSEGV");
break;
case 12: strcpy(sig_name,"SIGSYS");
break;
case 13: strcpy(sig_name,"SIGPIPE");
break;
case 14: strcpy(sig_name,"SIGALRM");
break;
case 15: strcpy(sig_name,"SIGTERM");
break;
case 16: strcpy(sig_name,"SIGURG");
break;
case 17: strcpy(sig_name,"SIGSTOP");
break;
case 18: strcpy(sig_name,"SIGSTP");
break;
case 19: strcpy(sig_name,"SIGCONT");
break;
case 20: strcpy(sig_name,"SIGCHLD");
break;
}
switch(CURR_PROC)
{
case PS_CHILD : strcpy(proc_name,"send_ps()");
break;
case FILTER_CHILD : strcpy(proc_name,"do_filter()");
break;
case READ_CHILD : strcpy(proc_name,"read_file()");
break;
default: strcpy(proc_name,"unknown proc");
}
abSleep(4,TRUE);
PAPClose(sock);
syslog(LOG_INFO,"PC-PAP : terminated by %s signal in %s",
sig_name, proc_name);
exit(LPD_ERROR);
}
/**************************************************************************
* Setup our signal handlers
*/
set_sigs()
{
int sig;
for ( sig = SIGINT; sig < NSIG; sig++ )
signal(sig, fatal);
signal(SIGHUP, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
}
/**************************************************************************
* Check out the arguements passed to us by LPD
*/
check_args(argc,argv)
int argc;
char *argv[];
{
int loop;
char *argp;
if((argv[0][0] == '/')||(argv[0][0] == '.'))/* Just want the basename */
{
argp = rindex(argv[0],'/');
strcpy(printer,++argp);
}
else
strcpy(printer,argv[0]);
for (loop = 1; loop < argc; loop++)
{
argp = argv[loop];
if (argp[0] == '-')
{
switch (argp[1])
{
case 'n':
strcpy(username,argv[++loop]);
break;
case 'h':
strcpy(hostname,argv[++loop]);
break;
}
}
else
strcpy(acct_file,argv[loop]);
}
}
/**************************************************************************
* Find the Appletalk laserwriter name from the cap.printers file
*/
char *find_lasername(queue)
char *queue;
{
static char buffer[100];
FILE *cap_file;
int num_bytes;
cap_file = fopen(CAP_PRINTERS,"r");
if (cap_file == NULL)
{
syslog(LOG_ERR,"PC-PAP : Cannot open Mapping File %s",
CAP_PRINTERS);
return(NULL);
}
while (!feof(cap_file))
{
fgets(buffer,100,cap_file);
if (!feof(cap_file))
{
if (buffer[0] != '#')
if (strcmp(queue,strtok(buffer,"=")) == 0)
{
fclose(cap_file);
return (strtok(NULL,"\n"));
}
}
}
fclose(cap_file);
return(NULL);
}
/**************************************************************************
* Make a PAP connection to the LaserWriter,
* Retries the connection 5 times then fails.
*/
int connect_to_laser(laser)
char *laser;
{
PAPStatusRec status;
AddrBlock addr;
int retry_minor = 0,
retry_major = 0,
sock,
comp_stat,
error;
char stat_string[100];
#ifdef DEBUG
fprintf(stderr,"\nOpening connection to %s\n",laser);
#endif DEBUG
sprintf(stat_string,"%s : Opening connection to %s",printer,laser);
write_status(stat_string);
abSleep(2,TRUE);
while((error = PAPOpen(&sock,laser,QUANTUM,&status,&comp_stat))!= noErr)
{
if (error != -1) /* Connection Error */
{
if (++retry_minor == 10)
{
sprintf(stat_string,"%s : Cannot connect to %s",
printer,laser);
write_status(stat_string);
retry_minor = 0;
if(++retry_major == 5)
return(0);
}
}
}
while(comp_stat > 0) /* incomplete connection */
{
addr.net = 0; /* sufficient */
abSleep(4,TRUE); /* protocol sleep for 1 second */
if (PAPStatus(laser,&status,&addr) >= 0)
store_status(status.StatusStr);
}
abSleep(4,TRUE);
return(sock);
}
/**************************************************************************
* Write PAP status message for the spooler to use
*/
store_status(status)
char *status;
{
int status_file;
char stat_line[200],
stat[40],
job[40],
*cp,
*fp;
strcpy(stat,"Unknown Status");
strcpy(job,"Unknown Job");
strncpy(stat_line,status + 1, *status);
cp = stat_line;
while(*cp != NULL)
{
if (strncmp(cp,"status:",7) == 0)
{
fp = stat;
cp += 7;
while((*cp != NULL) && (*cp != ';'))
{
*fp++ = *cp++;
}
*fp = NULL;
}
else
if (strncmp(cp,"job:",4) == 0)
{
fp = job;
cp += 5;
while((*cp != NULL) && (*cp != ';'))
{
*fp++ = *cp++;
}
*fp = NULL;
}
cp++;
}
sprintf(stat_line,"%s : Status = %s. Job = %s.",printer,stat,job);
unlink("new_status");
status_file = open("new_status",O_CREAT|O_WRONLY,0644);
if (status_file == -1)
return;
write(status_file,stat_line,strlen(stat_line));
write(status_file,"\n",1);
close(status_file);
rename("new_status","status");
}
/**************************************************************************
* Write TEXT status message for the spooler to use
*/
write_status(status)
char *status;
{
int status_file;
unlink("status");
status_file = open("status",O_CREAT|O_WRONLY,0644);
if (status_file == -1)
return;
write(status_file,status,strlen(status));
write(status_file,"\n",1);
close(status_file);
}
/**************************************************************************
* Fork and exec the appropriate filter for this data stream. Also
* fork a copy of ourself to handle reading the stdin and writing it
* to stdout. Filter_pipe goes from the original copy of us to the
* filter and printer_pipe goes from the stdout of the filter back to
* new copy of us (send_ps).
*/
exec_filter(filter)
filter_t *filter;
{
char *args[num_filter_args+1];
int index=1;
args[0] = filter->name;
while(filter->args[index-1][0] != '\000')
{
args[index] = filter->args[index-1];
index++;
}
args[index] = NULL;
index = 0;
#ifdef DEBUG
fprintf(stderr,"Path = %s\n",filter->path);
#endif DEBUG
execv(filter->path,args);
}
do_filter(lang,line,sock)
char *lang,
*line;
int sock;
{
int filter_pipe[2],
printer_pipe[2],
index = 0;
char *filter_name;
char arg_line[100];
while((strcmp(filters[index]->lang,lang)!=0) && (index<filter_offset))
index++;
if (index == filter_offset)
{
syslog(LOG_ERR,"PC-PAP : Bad Language %s",lang);
exit(LPD_ERROR);
}
pipe(filter_pipe);
pipe(printer_pipe);
if (fork() == 0) /* Child Process */
{
CURR_PROC = FILTER_CHILD;
dup2(filter_pipe[0],fileno(stdin));
dup2(printer_pipe[1],fileno(stdout));
close(filter_pipe[0]);
close(filter_pipe[1]);
close(printer_pipe[0]);
close(printer_pipe[1]);
exec_filter(filters[index]);
syslog(LOG_ERR,"PC-PAP : Bad exec for language %s",lang);
exit(LPD_ERROR);
}
else
{
if (fork() == 0) /*Second Child */
{
CURR_PROC = PS_CHILD;
dup2(printer_pipe[0],fileno(stdin));
close(filter_pipe[0]);
close(filter_pipe[1]);
close(printer_pipe[0]);
close(printer_pipe[1]);
send_ps(sock,NULL,0);
sleep(1);
exit(0);
}
else
{
CURR_PROC = READ_CHILD;
dup2(filter_pipe[1],fileno(stdout));
close(printer_pipe[0]);
close(printer_pipe[1]);
close(filter_pipe[0]);
close(filter_pipe[1]);
write(fileno(stdout),line,strlen(line));
read_file();
wait(0);
wait(0);
}
}
}
/**************************************************************************
* Scan and process the incoming file (including PS interpretation)
*/
process_file(sock)
int sock;
{
char stat_string[80],
line[100];
int index,
num_bytes;
sprintf(stat_string,"%s : Sending printjob to printer.",printer);
write_status(stat_string);
num_bytes = read(fileno(stdin),line,99);
line[num_bytes] = 0;
/* Is this a PostScript File ? */
for(index = 0; index < ps_offset; index++)
{
if(strncmp(ps_token[index],line,strlen(ps_token[index]))==0)
{
send_ps(sock,line,num_bytes);
return;
}
}
/* Can we match any other language on this file ? */
for(index = 0; index < magic_offset; index++)
{
if(strncmp(magics[index]->token,line,
strlen(magics[index]->token)) == 0)
{
do_filter(magics[index]->lang,line,sock);
return;
}
}
/* O.K. it must be a straight text file */
do_filter(TEXT_PS,line,sock);
}
/**************************************************************************
* Just read stdin and write it to stdout. This is easier than dup-ing
* stdin on the filter as we cannot lose the first X chars we have
* already read for the magic recognition.
*/
read_file()
{
char buff[BUF_SIZ];
int num_bytes;
int w_bytes;
do
{
num_bytes = read(fileno(stdin),buff,BUF_SIZ);
if (num_bytes != 0)
w_bytes = write(fileno(stdout),buff,num_bytes);
} while (num_bytes != 0);
close(fileno(stdout));
sleep(2);
}
/**************************************************************************
* Send the data pointed to by ch to the laser. Initiate a read from
* the laser. Show any change in printer status while we are waiting
* for the write to complete.
*/
pap_write(sock,ch,num,eof)
int sock;
char *ch;
int num,
eof;
{
int paperr,
wcomp;
PAPStatusRec status;
AddrBlock addr;
#ifdef DEBUG
fprintf(stderr,"In pap_write() num = %d, eof = %d\n",num,eof);
write(1,ch,num);
#endif DEBUG
if((num > 0) || (eof > 0))
{
paperr = PAPWrite(sock,ch,num,eof,&wcomp);
if (paperr < 0)
{
PAPClose(sock);
exit(LPD_REPRINT);
}
while (wcomp > 0)
{
#ifdef DEBUG
fprintf(stderr,"\nerror = %d, wcomp = %d, num = %d, eof = %d\n",
paperr, wcomp, num, eof);
#endif DEBUG
pap_read(sock);
abSleep(1,TRUE);
addr.net = 0;
if(PAPStatus(atalk_name,&status,&addr) >= 0)
store_status(status.StatusStr);
}
}
#ifdef DEBUG
fprintf(stderr,"Leaving pap_write()\n");
#endif DEBUG
}
/**************************************************************************
* Fudge up a non-blocking read from the laser. Discard anything we
* receive.
*/
pap_read(sock)
int sock;
{
if(r_eof == 1)
return(0);
if(r_comp > 0)
return(0);
if(r_comp == -1)
return(-1);
#ifdef DEBUG
if(r_len > 0)
write(1,r_buf,r_len);
#endif DEBUG
if(r_eof == 1)
return(1);
r_err = PAPRead(sock, r_buf, &r_len, &r_eof, &r_comp);
if(r_err = 0)
return(0);
else
return(-1);
}
/**************************************************************************
* Read the output of the filter (stdout of the filter maps to stdin of
* this process) and send it to the laserwriter via the PAP connection.
*/
send_ps(sock,line,line_len)
int sock;
char *line;
int line_len;
{
char buff[BUF_SIZ],
*c,
*c1;
int paperr,
wcomp,
num_bytes,
count,
index;
if (line != NULL)
{
c = line;
for(index = 0; index <line_len; index++)
if(*(c+index) == '\004')
*(c+index) = '\n';
pap_write(sock,line,line_len,FALSE);
}
do
{
if (r_eof == 1)
break;
num_bytes = read(fileno(stdin),buff,BUF_SIZ - 1);
#ifdef DEBUG
fprintf(stderr,"Num_Bytes in read = %d\n", num_bytes);
#endif DEBUG
c = buff;
index = 0;
count = 0;
while(count < num_bytes)
{
index++;
count++;
if (*(c+index) == '\004')
{
*(c+index) = '\n';
pap_write(sock,c,index,TRUE);
abSleep(4,TRUE);
c += index;
index = 0;
PAPClose(sock);
sock = connect_to_laser(atalk_name);
r_comp = 0;
r_eof = 0;
r_err = 0;
}
}
pap_write(sock,c,index,FALSE);
abSleep(4,TRUE);
}while (num_bytes != 0);
if (r_eof == 0)
{
pap_write(sock,c,0,TRUE);
pap_read(sock);
}
abSleep(2,TRUE);
}
/**************************************************************************
* Initialise the appletalk libraries (CAP), form the connection to the
* LaserWriter and process the data stream. Log the job to the printer
* log file.
*/
/* ARGS USED */
main(argc,argv)
int argc;
char *argv[];
{
char stat_string[80];
check_args(argc,argv);
load_config();
set_sigs();
atalk_name = find_lasername(printer);
if (atalk_name == NULL)
syslog(LOG_ERR,"PC-PAP : Could not map %s to a printer name",
printer);
abInit(FALSE);
nbpInit();
PAPInit();
ATPSetResponseTimeout(sectotick(60)); /* 1 Minutes */
sock = connect_to_laser(atalk_name);
process_file(sock);
abSleep(4,TRUE);
PAPClose(sock);
sprintf(stat_string,"%s : No Status (No Active Jobs)",printer);
write_status(stat_string);
}
\End\Of\Shar\
else
echo "will not over write ./pc-pap.c"
fi
if `test ! -s ./pc-pap.conf.example`
then
echo "writing ./pc-pap.conf.example"
cat > ./pc-pap.conf.example << '\End\Of\Shar\'
# @(#)/usr/local/lib/pc-pap.conf (Bond)
#
# Language configuration file for PC-PAP 31-Jan-1991 bambi at kirk.bu.oz.au
#
# Definitions of language recognition tokens, output filters and
# PostScript magics.
#
# There are four sections to the configuration :- postscript, text,
# filters and magics. The start of a section is defined by the
# section name preceded by a + on a line by itself.
#
# In the postscript section, the only entries are character tokens
# that define the start of a PostScript file. The tokens are terminated
# by a colon.
#
# The text section contains one definition being the path, name, and
# commandline options for a text to PostScript filter. Each field is
# colon separated. Up to ten command line options may be defined
# to represent argv[1] through argv[9] (argv[0] is set to the
# filter name.
#
# The filters section contains a list of filters used in pc-pap to
# convert a certain language into PostScript. The format of an entry is
# <ID>:<Path to filter>:<Name of filter>:<Arg1>:<Arg2>:<Arg N>:
#
# The final section, magics, contains the token to filter matchings
# for the language translations. The format of an entry is
# <Filter ID>:<Magic Token>:
#
# NOTE: The token must appear at the start of the first line of the file
# if it is to be recognised. The \ character is the standard
# escape and may be followed by any 3 digit decimal ASCII
# code (such as \004 for ^D or \058 for :).
#
# What appears below is a sample setup used on a host at Bond Uni.
#
+postscript
%!:
\004%!:
+text
/usr/local/lib/translators/t2ps:t2ps::
+filters
C_PS:/usr/local/lib/translators/pps:pps:c:
sh_PS:/usr/local/lib/translators/pps:pps:sh:
csh_PS:/usr/local/lib/translators/pps:pps:csh:
mail_PS:/usr/local/lib/translators/mp:mp::
+magics
C_PS:/*:
C_PS:#include<:
C_PS:#include <:
C_PS:static:
C_PS:#ifdef:
sh_PS:#!/bin/sh:
sh_PS:#! /bin/sh:
csh_PS:#!/bin/csh:
csh_PS:#! /bin/csh:
mail_PS:From :
mail_PS:From\58:
mail_PS:Path\58:
\End\Of\Shar\
else
echo "will not over write ./pc-pap.conf.example"
fi
if `test ! -s ./pc-pap.h`
then
echo "writing ./pc-pap.h"
cat > ./pc-pap.h << '\End\Of\Shar\'
/*
* Title : PC-PAP.h
* Author : David J. Highes bambi at kowande.bu.oz.au
* Date : 14-June-1990
* Dept : Network Management Group
* Bond University
*/
#define CAP_PRINTERS "/etc/cap.printers" /* Location of CAP file */
#define conf_dir "/usr/local/lib" /* Directory of config file */
#define conf_file "pc-pap.conf" /* Config file name */
#define lang_len 10 /* Max length of lang ID */
#define path_len 80 /* Max length of filter path */
#define name_len 10 /* Max length of filter name */
#define args_len 20 /* Max length of filter args */
#define magic_len 30 /* Max length of magic tokens */
#define num_filter_args 10 /* Max number args to filter */
#define STATUS 5 /* Check Status interval (sec)*/
#define QUANTUM 8 /* PAP Flow Quantum */
#define PS_CHILD 1 /* Debug */
#define FILTER_CHILD 2 /* Procedure */
#define READ_CHILD 3 /* Flags */
#define TEXT_PS "text_PS"
#define LPD_OK 0 /* LPD Good Print Exit Code */
#define LPD_REPRINT 1 /* LPD Reprint Exit Code */
#define LPD_ERROR 2 /* LPD Abort Job Exit Code */
typedef struct token_s
{
char token[magic_len];
char lang[lang_len];
} token_t;
typedef struct filter_s
{
char lang[lang_len];
char path[path_len];
char name[name_len];
char args[10][args_len];
} filter_t;
\End\Of\Shar\
else
echo "will not over write ./pc-pap.h"
fi
echo "Finished archive 1 of 1"
exit
More information about the Alt.sources
mailing list