home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / printer / pc_pap < prev    next >
Text File  |  1991-02-26  |  30KB  |  1,356 lines

  1. #!/bin/sh
  2. # to extract, remove the header and type "sh filename"
  3. # wrapped by bambi@kirk.bu.oz.au
  4. if `test ! -s ./Makefile`
  5. then
  6. echo "writing ./Makefile"
  7. cat > ./Makefile << '\End\Of\Shar\'
  8. #CFLAGS= -DDEBUG -g -c
  9. CFLAGS= -O -c
  10. OBJS= pc-pap.o config.o
  11.  
  12. .c.o:
  13.     cc $(CFLAGS) $*.c
  14.  
  15. all: pc-pap 
  16.  
  17. clean:
  18.     rm *.o pc-pap
  19.  
  20. pc-pap.o : pc-pap.c Makefile
  21. config.o : config.c Makefile
  22.  
  23. pc-pap : pc-pap.o config.o 
  24.     cc -o pc-pap $(OBJS) -lcap
  25.  
  26. install:
  27.     cp pc-pap /usr/local/lib/lpdfilters
  28.     chmod 760 /usr/local/lib/lpdfilters/pc-pap
  29. \End\Of\Shar\
  30. else
  31.   echo "will not over write ./Makefile"
  32. fi
  33. if `test ! -s ./README`
  34. then
  35. echo "writing ./README"
  36. cat > ./README << '\End\Of\Shar\'
  37. #      @(#)README  (Bond)  bambi
  38.  
  39.  
  40.  
  41.         Title    : PC-PAP.c
  42.         Author    : David J. Hughes     bambi@kirk.bu.oz.au
  43.         Date    : 27-Jan-1991
  44.         Dept    : Communications Development and Operations
  45.               Bond University
  46.  
  47.     
  48.     This program is a replacement PAP based lpd input filter for
  49.     the standard CAP papif.  At the simplest level, it performs 
  50.     the same function as papif (send a printjob to an appletalk
  51.     based laserwriter).  It also provides for definable language
  52.     recognition and filtering based on the contents of the first
  53.     line of the print job (such as a PostScript magic or #! /bin/sh
  54.     in shell scripts).  It also splits PostScript printjobs into
  55.     individual PAP connections.  This is essential if IBM PC
  56.     based applications, such as MS-Word, print via this queue.
  57.  
  58.      As most PostScript PC print jobs consist of a procedure set 
  59.      followed by a document, the print job sent to the laser
  60.      contains a ^D in the middle.  An Apple Laser will see this 
  61.      and flush the job untill end of file.  Unfortunately, if the
  62.      laser is connected to appletalk, it assumes that end of file is
  63.      when the PAP connection is dropped.  This is why each 
  64.      PostScript print job is split into it's own PAP connection.
  65.  
  66.     To configure the language recognition features edit the
  67.     pc-pap.conf file to represent your local site.  Details of the
  68.     file format are outlined in the pc-pap.conf.example file.  When
  69.     the configuration file is completed, it shoulod be installed as
  70.     /usr/local/lib/pc-pap.conf.  To check the configuration file,
  71.     run pc-pap from the commandline.  The first task it performs is
  72.     to parse and load the configuration from file.  Any errors found
  73.     will be reported to the terminal (including location and type
  74.     of error).
  75.  
  76.     Installation of the pc-pap filter is the same as the
  77.     installation of papif.  Basically, the software uses the program
  78.     name (argv[0]) as the name of the printer to which the data
  79.     should be sent.  To install the filter for a printer called
  80.     admin-laser, create a sym-link to pc-pap called admin-laser.
  81.     Set the if= field in the /etc/printcap file to point to the
  82.     sym-link as the printers input filter.
  83.  
  84.     The only other file that is used by pc-pap is the
  85.     /etc/cap.printers file.  It expects it to be in the same format
  86.     as is specified in the CAP 5.0 distribution.
  87.  
  88.     Testing of the filter can be performed by redirecting an input
  89.     file into the sym-link (eg. admin-laser < test.ps).  If an error
  90.     is encountered, it will be logged via syslog.
  91. \End\Of\Shar\
  92. else
  93.   echo "will not over write ./README"
  94. fi
  95. if `test ! -s ./config.c`
  96. then
  97. echo "writing ./config.c"
  98. cat > ./config.c << '\End\Of\Shar\'
  99. /*
  100.  *              Title   : config.c
  101.  *              Author  : David J. Hughes     bambi@kirk.bu.oz.au
  102.  *              Date    : 27-Jan-1991
  103.  *              Dept    : Communications Development and Operations
  104.  *                        Bond University
  105.  *
  106.  *    Routines to parse and load the configuration file
  107.  */
  108.  
  109.  
  110. #include <stdio.h>
  111. #include <syslog.h>
  112. #include <strings.h>
  113. #include <malloc.h>
  114. #include "pc-pap.h"
  115.  
  116. char        *ps_token[10];                    /* List of tokens */
  117. token_t        *magics[50];
  118. filter_t    *filters[10];
  119. int        magic_offset = 0,
  120.             ps_offset = 0,
  121.            filter_offset = 0,
  122.         ps_found = 0,
  123.            text_found = 0;
  124.  
  125.  
  126. /*
  127. ** SUBST_ASCII :  Check the string for any embedded ASCII values and
  128. **          convert them to there actual character codes.
  129. **
  130. */
  131.  
  132.  
  133. char * subst_ascii(str)
  134.     char    *str;
  135. {
  136.     static    char ret_str[80];
  137.      char    *cp1,
  138.         *cp2,
  139.         ascii[4];
  140.  
  141.     strcpy(ret_str,"");
  142.     cp1 = str;
  143.     cp2 = ret_str;
  144.     while(*cp1 != NULL)
  145.     {
  146.         if(*cp1 != '\\')
  147.             *cp2 = *cp1;
  148.         else
  149.         {
  150.             ascii[0] = *++cp1;
  151.             ascii[1] = *++cp1;
  152.             ascii[2] = *++cp1;
  153.             ascii[3] = 0;
  154.             *cp2 = (char) atoi(ascii);
  155.         }
  156.         cp1++;
  157.         cp2++;
  158.     }
  159.     *cp2 = 0;
  160.     return(ret_str);
  161. }
  162.  
  163.  
  164. /*
  165. ** BAD_CONFIG :  Report configuration error.
  166. **
  167. */
  168.  
  169. bad_config(line,error)
  170.     int    line;
  171.     char    *error;
  172. {
  173.     fprintf(stderr,"\n\nPC-PAP : Error in configuration file at line %d.",
  174.         line);
  175.     if (error != NULL)
  176.         fprintf(stderr,"\n         %s.\n",error);
  177.     fprintf(stderr,"\nExiting \007\n");
  178.     syslog(LOG_DEBUG,"PC-PAP : Error in config at line %d",line);
  179.     exit(1);
  180. }
  181.  
  182.  
  183. /*
  184. ** READ_PS  :  load the PostScript magic tokens
  185. **
  186. */
  187.  
  188. read_ps(line,line_num)
  189.     char     *line;
  190.     int    line_num;
  191. {
  192.     char    *token,
  193.         *store;
  194.  
  195.     if (index(line,':') == NULL)
  196.         bad_config(line_num,"No terminator on PostScript magic token");
  197.     token = strtok(line,":");
  198.     if (token == NULL)
  199.         bad_config(line_num,"No token defined");
  200.     store = (char *) malloc(strlen(token)+1);
  201.     strcpy(store,subst_ascii(token));
  202.     ps_token[ps_offset++] = store;
  203.     ps_found = 1;
  204. }
  205.  
  206.  
  207. /*
  208. ** STORE_FILTER  :  Write a set filter definition into the filter vector.
  209. **
  210. */
  211.  
  212. store_filter(lang,line,line_num)
  213.     char    *lang,
  214.         *line;
  215.     int    line_num;
  216. {
  217.     char        *token,
  218.             error_msg[80];
  219.     filter_t    *tmp_filter;
  220.     int        token_count = 0,
  221.             arg_num = 0;
  222.  
  223.     tmp_filter = (filter_t *) malloc(sizeof(filter_t));
  224.     if(strlen(lang) >= lang_len)
  225.     {
  226.         free(tmp_filter);
  227.         sprintf(error_msg,"Language id too long.  Max is %d characters",
  228.             lang_len);
  229.         bad_config(line_num,error_msg);
  230.     }
  231.     strcpy(tmp_filter->lang,subst_ascii(lang));
  232.  
  233.     if((token = strtok(line,":")) == NULL)
  234.     {
  235.         free(tmp_filter);
  236.         bad_config(line_num,"Bad filter definition (2nd Token)");
  237.     }
  238.     if(strlen(token) >= path_len)
  239.     {
  240.         free(tmp_filter);
  241.         sprintf(error_msg,"Filter path too long.  Max is %d characters",
  242.             path_len);
  243.         bad_config(line_num,error_msg);
  244.     }
  245.     strcpy(tmp_filter->path,subst_ascii(token));
  246.  
  247.     if((token = strtok(NULL,":")) == NULL)
  248.     {
  249.         free(tmp_filter);
  250.         bad_config(line_num,"Bad text filter definition (3nd Token)");
  251.     }
  252.     if(strlen(token) >= name_len)
  253.     {
  254.         free(tmp_filter);
  255.         sprintf(error_msg,"Filter name too long.  Max is %d characters",
  256.             name_len);
  257.         bad_config(line_num,error_msg);
  258.     }
  259.     strcpy(tmp_filter->name,subst_ascii(token));
  260.  
  261.     
  262.     while((token = strtok(NULL,":")) != NULL)
  263.     {
  264.         if(strlen(token) >= args_len)
  265.         {
  266.             free(tmp_filter);
  267.             sprintf(error_msg,
  268.                "Filter arguements too long.  Max is %d characters",
  269.                 args_len);
  270.             bad_config(line_num,error_msg);
  271.         }
  272.         strcpy(tmp_filter->args[arg_num++],subst_ascii(token));
  273.     }
  274.     while(arg_num < num_filter_args)
  275.         tmp_filter->args[arg_num++][0] = NULL;
  276.     filters[filter_offset++] = tmp_filter;
  277. }
  278.  
  279.  
  280. /*
  281. ** READ_TEXT  :  load the Text to PostScript filter details
  282. **
  283. */
  284.  
  285.  
  286. read_text(line, line_num)
  287.     char     *line;
  288.     int    line_num;
  289. {
  290.     char        *token;
  291.  
  292.     store_filter(TEXT_PS,line,line_num);
  293.     text_found = 1;
  294. }
  295.  
  296.  
  297. /*
  298. ** READ_FILTERS  :  load the language filter definitions
  299. **
  300. */
  301.  
  302. read_filters(line, line_num)
  303.     char     *line;
  304.     int    line_num;
  305. {
  306.     char    *lang,
  307.         *rest;
  308.     
  309.     lang = strtok(line,":");
  310.     rest = strtok(NULL,"\n");
  311.     store_filter(lang,rest,line_num);
  312. }
  313.  
  314.  
  315. /*
  316. ** READ_MAGICS  :  load the magic tokens definitions
  317. **
  318. */
  319.  
  320. read_magics(line,line_num)
  321.     char     *line;
  322. {
  323.     char        *token,
  324.             error_msg[80];
  325.     token_t        *tmp_token;
  326.     int        token_count = 0;
  327.  
  328.     tmp_token = (token_t *) malloc(sizeof(token_t));
  329.     if((token = strtok(line,":")) == NULL)
  330.         bad_config(line_num,"Missing tokens");
  331.     if(strlen(token) >= lang_len)
  332.     {
  333.         free(tmp_token);
  334.         sprintf(error_msg,"Language id too long.  Max is %d characters",
  335.             lang_len);
  336.         bad_config(line_num,error_msg);
  337.     }
  338.     strcpy(tmp_token->lang,subst_ascii(token));
  339.  
  340.     if((token = strtok(NULL,":")) != NULL)
  341.     {
  342.         if(strlen(token) >= magic_len)
  343.         {
  344.             free(tmp_token);
  345.             sprintf(error_msg,
  346.                "Magic token too long.  Max is %d characters",
  347.                 magic_len);
  348.             bad_config(line_num,error_msg);
  349.         }
  350.         strcpy(tmp_token->token, subst_ascii(token));
  351.     }
  352.     else
  353.         bad_config(line_num,"No magic string supplied.");
  354.     magics[magic_offset++] = tmp_token;
  355. }
  356.  
  357.  
  358. /*
  359. ** LOAD_CONFIG  :  load the configuration file into internal structures.
  360. **
  361. **      Note :  The internal stat machine has the following states :-
  362. **
  363. **
  364. **                      0.  Starting config read
  365. **                      1.  Reading PostScript section
  366. **                      2.  Reading Text section
  367. **                      3.  Reading Filters section
  368. **            4.  Reading Magics section
  369. */
  370.  
  371.  
  372. load_config()
  373. {
  374.         FILE    *conf;
  375.         char    conf_line[100],
  376.                 conf_path[100],
  377.         *token;
  378.         int     state = 0,
  379.                 line_num=0;
  380.  
  381.         sprintf(conf_path,"%s/%s",conf_dir,conf_file);
  382.         conf = fopen(conf_path,"r");
  383.         if (conf == NULL)
  384.         {
  385.                 fprintf(stderr,"\007\nPC-PAP :  Could not open configuration");
  386.                 fprintf(stderr," file.  Aborting.\n\n");
  387.         syslog(LOG_DEBUG,"PC-PAP : Could not open configuration file");
  388.                 exit(1);
  389.         }
  390.         while (!feof(conf))
  391.         {
  392.                 fgets(conf_line,99,conf);
  393.         conf_line[strlen(conf_line)-1] = 0;
  394.                 line_num++;
  395.                 if (!feof(conf))
  396.                 {
  397.                         switch(conf_line[0])
  398.                         {
  399.                                 case '#':               /* Comment */
  400.                                 case '\0':              /* Blank Line */
  401.                                         break;
  402.                 case ' ':
  403.                 case '\t':
  404.                     bad_config(line_num,
  405.                         "Leading white space");
  406.                     break;
  407.  
  408.                                 case '+':                /* State change */
  409.                                         token = strtok(conf_line+1," \n");
  410.                                         if (strcmp(token,"postscript") == 0)
  411.                                                state = 1;
  412.                     else
  413.                                         if (strcmp(token,"text") == 0)
  414.                                                 state = 2;
  415.                     else
  416.                                         if (strcmp(token,"filters") == 0)
  417.                                                state = 3;
  418.                     else
  419.                                         if (strcmp(token,"magics") == 0)
  420.                                                state = 4;
  421.                     else
  422.                         bad_config(line_num,
  423.                            "Unknown section header");
  424.                     break;
  425.                                 default:
  426.                     switch(state)
  427.                     {
  428.                         case 0: 
  429.                             bad_config(line_num,
  430.                              "Section not defined");
  431.                             break;
  432.                         case 1: 
  433.                             read_ps(conf_line, 
  434.                                 line_num);
  435.                             break;
  436.                         case 2: 
  437.                             read_text(conf_line,
  438.                                 line_num);
  439.                             break;
  440.                         case 3: 
  441.                             read_filters(conf_line,
  442.                                 line_num);
  443.                             break;
  444.                         case 4: 
  445.                             read_magics(conf_line,
  446.                                 line_num);
  447.                             break;
  448.                     }
  449.             }
  450.                 }
  451.         }
  452. }
  453. \End\Of\Shar\
  454. else
  455.   echo "will not over write ./config.c"
  456. fi
  457. if `test ! -s ./pc-pap.c`
  458. then
  459. echo "writing ./pc-pap.c"
  460. cat > ./pc-pap.c << '\End\Of\Shar\'
  461. /*
  462.  *        Title    : PC-PAP.c
  463.  *        Author    : David J. Hughes     bambi@kirk.bu.oz.au
  464.  *        Date    : 14-June-1990
  465.  *        Dept    : Communications Development and Operations
  466.  *              Bond University
  467.  *
  468.  *--------------------------------------------------------------------------
  469.  * Edit history
  470.  *
  471.  * 14-June-1990            bambi
  472.  *
  473.  *    Initial development    
  474.  *--------------------------------------------------------------------------
  475.  * 27-Jan-1991            bambi
  476.  *
  477.  *    Remove the hard-coded configuration for language recognition and
  478.  *    use a config file to be read at run-time.  
  479.  *
  480.  *    Fix time-out error when Laser returns a PAP eof flag to us on a 
  481.  *    read.  
  482.  *
  483.  *    Include Job details in the lpq status file so that PC users can see the
  484.  *    name and type of job being printed (only supported in certain 
  485.  *    applications such as Excel, PageMaker, Word for Windows etc.)
  486.  *
  487.  *    Fix up the handling of printer error returns such as "Out of
  488.  *    paper"
  489.  *--------------------------------------------------------------------------
  490.  *
  491.  */
  492.  
  493.  
  494. #include <stdio.h>
  495. #include <syslog.h>
  496. #include <varargs.h>
  497. #include <strings.h>
  498. #include <signal.h>
  499. #include <limits.h>
  500. #include <sys/types.h>
  501. #include <sys/time.h>
  502. #include <sys/file.h>
  503. #include <netat/appletalk.h>
  504. #include <netat/compat.h>
  505. #include "pc-pap.h"
  506.  
  507. #define  BUF_SIZ    QUANTUM * PAPSegSize
  508.  
  509.  
  510. /*
  511. ** Global variable definition section
  512. */
  513.  
  514. char    printer[20],
  515.     username[20],
  516.     hostname[20],
  517.     acct_file[80],
  518.     *atalk_name,
  519.          r_buf[100];            /* PAPRead buffer */
  520.  
  521. int     sock,                           /* Must be global for signal handler */
  522.         r_comp =     0,        /* PAPRead completion flag */
  523.         r_len =     0,        /* PAPRead data length */
  524.         r_err =     0,
  525.         r_eof =     0,
  526.        CURR_PROC =     0;
  527.  
  528.  
  529.  
  530. /*
  531. ** External variable definition section
  532. */
  533.  
  534.  
  535. extern    char        *ps_token[];
  536. extern    token_t        *magics[];
  537. extern    filter_t    *filters[];
  538. extern    int        magic_offset,
  539.             ps_offset,
  540.             filter_offset;
  541.             
  542.  
  543. /**************************************************************************
  544.  * Close down the PAP Connection and exit REPRINT
  545.  */
  546.  
  547. fatal(sig)
  548.     int    sig;
  549. {
  550.     char    sig_name[15],
  551.         proc_name[15];
  552.  
  553.  
  554.     switch (sig)
  555.     {
  556.         case 1: strcpy(sig_name,"SIGHUP");
  557.             break;
  558.         case 2: strcpy(sig_name,"SIGINT");
  559.             break;
  560.         case 3: strcpy(sig_name,"SIGQUIT");
  561.             break;
  562.         case 4: strcpy(sig_name,"SIGILL");
  563.             break;
  564.         case 5: strcpy(sig_name,"SIGTRAP");
  565.             break;
  566.         case 6: strcpy(sig_name,"SIGIOT");
  567.             break;
  568.         case 7: strcpy(sig_name,"SIGEMT");
  569.             break;
  570.         case 8: strcpy(sig_name,"SIGFPE");
  571.             break;
  572.         case 9: strcpy(sig_name,"SIGKILL");
  573.             break;
  574.         case 10: strcpy(sig_name,"SIGBUS");
  575.             break;
  576.         case 11: strcpy(sig_name,"SIGSEGV");
  577.             break;
  578.         case 12: strcpy(sig_name,"SIGSYS");
  579.             break;
  580.         case 13: strcpy(sig_name,"SIGPIPE");
  581.             break;
  582.         case 14: strcpy(sig_name,"SIGALRM");
  583.             break;
  584.         case 15: strcpy(sig_name,"SIGTERM");
  585.             break;
  586.         case 16: strcpy(sig_name,"SIGURG");
  587.             break;
  588.         case 17: strcpy(sig_name,"SIGSTOP");
  589.             break;
  590.         case 18: strcpy(sig_name,"SIGSTP");
  591.             break;
  592.         case 19: strcpy(sig_name,"SIGCONT");
  593.             break;
  594.         case 20: strcpy(sig_name,"SIGCHLD");
  595.             break;
  596.     }        
  597.     switch(CURR_PROC)
  598.     {
  599.         case PS_CHILD : strcpy(proc_name,"send_ps()");
  600.             break;
  601.         case FILTER_CHILD : strcpy(proc_name,"do_filter()");
  602.             break;
  603.         case READ_CHILD : strcpy(proc_name,"read_file()");
  604.             break;
  605.         default: strcpy(proc_name,"unknown proc");
  606.     }
  607.     abSleep(4,TRUE);
  608.     PAPClose(sock);
  609.     syslog(LOG_INFO,"PC-PAP : terminated by %s signal in %s",
  610.         sig_name, proc_name);
  611.     exit(LPD_ERROR);
  612. }
  613.  
  614.  
  615.  
  616.  
  617.  
  618. /**************************************************************************
  619.  * Setup our signal handlers
  620.  */
  621.  
  622. set_sigs()
  623. {
  624.     int    sig;
  625.  
  626.         for ( sig = SIGINT; sig < NSIG; sig++ )
  627.                 signal(sig, fatal);
  628.         signal(SIGHUP, SIG_IGN);
  629.     signal(SIGCHLD, SIG_IGN);
  630. }
  631.  
  632.  
  633.  
  634.  
  635.  
  636. /**************************************************************************
  637.  * Check out the arguements passed to us by LPD
  638.  */
  639.  
  640. check_args(argc,argv)
  641.     int    argc;
  642.     char    *argv[];
  643. {
  644.     int    loop;
  645.     char    *argp;
  646.  
  647.     if((argv[0][0] == '/')||(argv[0][0] == '.'))/* Just want the basename */
  648.     {
  649.         argp = rindex(argv[0],'/');
  650.         strcpy(printer,++argp);
  651.     }
  652.     else
  653.         strcpy(printer,argv[0]);
  654.  
  655.     for (loop = 1; loop < argc; loop++)
  656.     {
  657.         argp = argv[loop];
  658.         if (argp[0] == '-')
  659.         {
  660.             switch (argp[1])
  661.             {
  662.                 case 'n':
  663.                     strcpy(username,argv[++loop]);
  664.                     break;
  665.             
  666.                 case 'h':
  667.                     strcpy(hostname,argv[++loop]);
  668.                     break;
  669.             }
  670.         }
  671.         else
  672.             strcpy(acct_file,argv[loop]);
  673.     }
  674. }
  675.  
  676.  
  677.  
  678.  
  679.  
  680.  
  681. /**************************************************************************
  682.  * Find the Appletalk laserwriter name from the cap.printers file
  683.  */
  684.  
  685.  
  686. char *find_lasername(queue)
  687.     char    *queue;
  688. {
  689.     static    char    buffer[100];
  690.     FILE    *cap_file;
  691.     int    num_bytes;
  692.  
  693.     cap_file = fopen(CAP_PRINTERS,"r");
  694.     if (cap_file == NULL)
  695.     {
  696.         syslog(LOG_ERR,"PC-PAP : Cannot open Mapping File %s",
  697.             CAP_PRINTERS);
  698.         return(NULL);
  699.     }
  700.     while (!feof(cap_file))
  701.     {
  702.         fgets(buffer,100,cap_file);
  703.         if (!feof(cap_file))
  704.         {
  705.             if (buffer[0] != '#')
  706.                 if (strcmp(queue,strtok(buffer,"=")) == 0)
  707.                 {
  708.                     fclose(cap_file);
  709.                     return (strtok(NULL,"\n"));
  710.                 }
  711.         }
  712.     }
  713.     fclose(cap_file);
  714.     return(NULL);
  715. }
  716.  
  717.  
  718.  
  719.  
  720.  
  721. /**************************************************************************
  722.  * Make a PAP connection to the LaserWriter,
  723.  *     Retries the connection 5 times then fails.
  724.  */
  725.  
  726. int connect_to_laser(laser)
  727.     char    *laser;
  728. {
  729.     PAPStatusRec    status;
  730.     AddrBlock     addr;
  731.     int        retry_minor = 0,    
  732.             retry_major = 0,
  733.             sock,
  734.             comp_stat,
  735.             error;
  736.     char        stat_string[100];
  737.  
  738. #ifdef DEBUG
  739.     fprintf(stderr,"\nOpening connection to %s\n",laser);
  740. #endif DEBUG
  741.     sprintf(stat_string,"%s : Opening connection to %s",printer,laser);
  742.     write_status(stat_string);
  743.     abSleep(2,TRUE);
  744.     while((error = PAPOpen(&sock,laser,QUANTUM,&status,&comp_stat))!= noErr)
  745.     {
  746.         if (error != -1)   /* Connection Error */
  747.         {
  748.             if (++retry_minor == 10)
  749.             {
  750.                 sprintf(stat_string,"%s : Cannot connect to %s",
  751.                     printer,laser);
  752.                 write_status(stat_string);
  753.                 retry_minor = 0;
  754.                 if(++retry_major == 5)
  755.                     return(0);
  756.             }
  757.         }
  758.     }
  759.     while(comp_stat > 0)    /* incomplete connection */
  760.     {
  761.         addr.net = 0;             /* sufficient */
  762.         abSleep(4,TRUE);    /* protocol sleep for 1 second */
  763.         if (PAPStatus(laser,&status,&addr) >= 0)
  764.             store_status(status.StatusStr);
  765.     }
  766.     abSleep(4,TRUE);
  767.     return(sock);
  768. }
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776. /**************************************************************************
  777.  * Write PAP status message for the spooler to use
  778.  */
  779.  
  780. store_status(status)
  781.     char    *status;
  782. {
  783.     int    status_file;
  784.     char    stat_line[200],
  785.         stat[40],
  786.         job[40],
  787.         *cp,
  788.         *fp;
  789.  
  790.     strcpy(stat,"Unknown Status");
  791.     strcpy(job,"Unknown Job");
  792.     strncpy(stat_line,status + 1, *status);
  793.     cp = stat_line;
  794.     while(*cp != NULL)
  795.     {
  796.         if (strncmp(cp,"status:",7) == 0)
  797.         {
  798.             fp = stat;
  799.             cp += 7;
  800.             while((*cp != NULL) && (*cp != ';'))
  801.             {
  802.                 *fp++ = *cp++;
  803.             }
  804.             *fp = NULL;
  805.         }
  806.         else
  807.         if (strncmp(cp,"job:",4) == 0)
  808.         {
  809.             fp = job;
  810.             cp += 5;
  811.             while((*cp != NULL) && (*cp != ';'))
  812.             {
  813.                 *fp++ = *cp++;
  814.             }
  815.             *fp = NULL;
  816.         }
  817.         cp++;
  818.     }
  819.     sprintf(stat_line,"%s : Status = %s.  Job = %s.",printer,stat,job);
  820.     unlink("new_status");
  821.     status_file = open("new_status",O_CREAT|O_WRONLY,0644);
  822.     if (status_file == -1)
  823.         return;
  824.     write(status_file,stat_line,strlen(stat_line));
  825.     write(status_file,"\n",1);
  826.     close(status_file);
  827.     rename("new_status","status");
  828. }
  829.  
  830.  
  831. /**************************************************************************
  832.  * Write TEXT status message for the spooler to use
  833.  */
  834.  
  835. write_status(status)
  836.     char    *status;
  837. {
  838.     int    status_file;
  839.  
  840.     unlink("status");
  841.     status_file = open("status",O_CREAT|O_WRONLY,0644);
  842.     if (status_file == -1)
  843.         return;
  844.     write(status_file,status,strlen(status));
  845.     write(status_file,"\n",1);
  846.     close(status_file);
  847. }
  848.  
  849.  
  850.  
  851.  
  852.  
  853. /**************************************************************************
  854.  * Fork and exec the appropriate filter for this data stream.  Also
  855.  * fork a copy of ourself to handle reading the stdin and writing it
  856.  * to stdout.  Filter_pipe goes from the original copy of us to the
  857.  * filter and printer_pipe goes from the stdout of the filter back to
  858.  * new copy of us (send_ps).
  859.  */
  860.  
  861. exec_filter(filter)
  862.     filter_t    *filter;
  863. {
  864.     char        *args[num_filter_args+1];
  865.     int        index=1;
  866.  
  867.     args[0] = filter->name;
  868.     while(filter->args[index-1][0] != '\000')
  869.     {
  870.         args[index] = filter->args[index-1];
  871.         index++;
  872.     }
  873.     args[index] = NULL;
  874.     index = 0;
  875. #ifdef     DEBUG
  876.     fprintf(stderr,"Path = %s\n",filter->path);
  877. #endif    DEBUG
  878.     execv(filter->path,args);
  879. }
  880.  
  881.  
  882. do_filter(lang,line,sock)
  883.     char     *lang,
  884.             *line;
  885.     int    sock;
  886. {
  887.     int    filter_pipe[2],
  888.         printer_pipe[2],
  889.         index = 0;
  890.     char    *filter_name;
  891.     char    arg_line[100];
  892.  
  893.     
  894.     while((strcmp(filters[index]->lang,lang)!=0) && (index<filter_offset))
  895.         index++;
  896.  
  897.     if (index == filter_offset)
  898.     {
  899.         syslog(LOG_ERR,"PC-PAP : Bad Language %s",lang);
  900.         exit(LPD_ERROR);
  901.     }
  902.     pipe(filter_pipe);
  903.     pipe(printer_pipe);
  904.     if (fork() == 0)    /* Child Process */
  905.     {
  906.         CURR_PROC = FILTER_CHILD;
  907.         dup2(filter_pipe[0],fileno(stdin));    
  908.         dup2(printer_pipe[1],fileno(stdout));
  909.         close(filter_pipe[0]);
  910.         close(filter_pipe[1]);
  911.         close(printer_pipe[0]);
  912.         close(printer_pipe[1]);
  913.         exec_filter(filters[index]);
  914.         syslog(LOG_ERR,"PC-PAP : Bad exec for language %s",lang);
  915.         exit(LPD_ERROR);
  916.     }
  917.     else
  918.     {
  919.         if (fork() == 0) /*Second Child */
  920.         {
  921.             CURR_PROC = PS_CHILD;
  922.             dup2(printer_pipe[0],fileno(stdin));
  923.             close(filter_pipe[0]);
  924.             close(filter_pipe[1]);
  925.             close(printer_pipe[0]);
  926.             close(printer_pipe[1]);
  927.             send_ps(sock,NULL,0);
  928.             sleep(1);
  929.             exit(0);
  930.         }
  931.         else
  932.         {
  933.             CURR_PROC = READ_CHILD;
  934.             dup2(filter_pipe[1],fileno(stdout));
  935.             close(printer_pipe[0]);
  936.             close(printer_pipe[1]);
  937.             close(filter_pipe[0]);
  938.             close(filter_pipe[1]);
  939.             write(fileno(stdout),line,strlen(line));
  940.             read_file();
  941.             wait(0);
  942.             wait(0);
  943.         }
  944.     }
  945. }
  946.  
  947.  
  948.  
  949.  
  950. /**************************************************************************
  951.  *  Scan and process the incoming file (including PS interpretation)
  952.  */
  953.  
  954. process_file(sock)
  955.     int    sock;
  956. {
  957.     char    stat_string[80],
  958.         line[100];
  959.     int    index,
  960.         num_bytes;
  961.  
  962.     
  963.  
  964.     sprintf(stat_string,"%s : Sending printjob to printer.",printer);
  965.     write_status(stat_string);
  966.  
  967.     num_bytes = read(fileno(stdin),line,99);
  968.     line[num_bytes] = 0;
  969.     
  970.     /* Is this a PostScript File ? */
  971.  
  972.     for(index = 0; index < ps_offset; index++)
  973.     {
  974.         if(strncmp(ps_token[index],line,strlen(ps_token[index]))==0)
  975.         {
  976.             send_ps(sock,line,num_bytes);
  977.             return;
  978.         }
  979.     }
  980.     
  981.     /* Can we match any other language on this file ? */
  982.  
  983.     for(index = 0; index < magic_offset; index++)
  984.     {
  985.         if(strncmp(magics[index]->token,line,
  986.            strlen(magics[index]->token)) == 0)
  987.         {
  988.             do_filter(magics[index]->lang,line,sock);
  989.             return;
  990.         }
  991.     }
  992.         
  993.     /* O.K. it must be a straight text file */
  994.  
  995.     do_filter(TEXT_PS,line,sock);
  996. }
  997.  
  998.  
  999.  
  1000.  
  1001.  
  1002. /**************************************************************************
  1003.  *  Just read stdin and write it to stdout.  This is easier than dup-ing
  1004.  *  stdin on the filter as we cannot lose the first X chars we have
  1005.  *  already read for the magic recognition.
  1006.  */
  1007.  
  1008.  
  1009. read_file()
  1010. {
  1011.     char    buff[BUF_SIZ];
  1012.     int    num_bytes;
  1013.     int    w_bytes;
  1014.  
  1015.     do
  1016.     {
  1017.         num_bytes = read(fileno(stdin),buff,BUF_SIZ);
  1018.         if (num_bytes != 0)
  1019.             w_bytes = write(fileno(stdout),buff,num_bytes);
  1020.     } while (num_bytes != 0);
  1021.     close(fileno(stdout));
  1022.     sleep(2);
  1023. }
  1024.  
  1025.  
  1026.  
  1027. /**************************************************************************
  1028.  *  Send the data pointed to by ch to the laser. Initiate a read from
  1029.  *  the laser.  Show any change in printer status while we are waiting
  1030.  *  for the write to complete.
  1031.  */
  1032.  
  1033.  
  1034. pap_write(sock,ch,num,eof)
  1035.     int    sock;
  1036.     char    *ch;
  1037.     int    num,
  1038.            eof;
  1039. {
  1040.     int    paperr,
  1041.         wcomp;
  1042.     PAPStatusRec    status;
  1043.     AddrBlock    addr;
  1044.  
  1045. #ifdef    DEBUG
  1046.         fprintf(stderr,"In pap_write() num = %d, eof = %d\n",num,eof);
  1047.         write(1,ch,num);
  1048. #endif    DEBUG
  1049.  
  1050.     if((num > 0) || (eof > 0))
  1051.     {
  1052.         paperr = PAPWrite(sock,ch,num,eof,&wcomp);
  1053.         if (paperr < 0)
  1054.         {
  1055.             PAPClose(sock);
  1056.             exit(LPD_REPRINT);
  1057.         }
  1058.         while (wcomp > 0)
  1059.         {
  1060. #ifdef DEBUG
  1061.             fprintf(stderr,"\nerror = %d, wcomp = %d, num = %d, eof = %d\n",
  1062.                 paperr, wcomp, num, eof);
  1063. #endif DEBUG
  1064.             pap_read(sock);
  1065.             abSleep(1,TRUE);
  1066.             addr.net = 0;
  1067.             if(PAPStatus(atalk_name,&status,&addr) >= 0)
  1068.                 store_status(status.StatusStr);
  1069.         }
  1070.     }
  1071. #ifdef     DEBUG
  1072.     fprintf(stderr,"Leaving pap_write()\n");
  1073. #endif    DEBUG
  1074. }
  1075.  
  1076.  
  1077.  
  1078. /**************************************************************************
  1079.  *  Fudge up a non-blocking read from the laser.  Discard anything we
  1080.  *  receive.
  1081.  */
  1082.  
  1083. pap_read(sock)
  1084.     int    sock;
  1085. {
  1086.     if(r_eof == 1)
  1087.         return(0);
  1088.     if(r_comp > 0)
  1089.         return(0);
  1090.  
  1091.     if(r_comp == -1)
  1092.         return(-1);
  1093.  
  1094. #ifdef    DEBUG
  1095.     if(r_len > 0)
  1096.         write(1,r_buf,r_len);
  1097. #endif    DEBUG
  1098.     if(r_eof == 1)
  1099.         return(1);
  1100.     r_err = PAPRead(sock, r_buf, &r_len, &r_eof, &r_comp);
  1101.     if(r_err = 0)
  1102.         return(0);
  1103.     else
  1104.         return(-1);
  1105. }
  1106.  
  1107.         
  1108. /**************************************************************************
  1109.  *  Read the output of the filter (stdout of the filter maps to stdin of
  1110.  *  this process) and send it to the laserwriter via the PAP connection.
  1111.  */
  1112.  
  1113. send_ps(sock,line,line_len)
  1114.     int    sock;
  1115.     char    *line;
  1116.     int    line_len;
  1117. {
  1118.  
  1119.     char    buff[BUF_SIZ],
  1120.         *c,
  1121.         *c1;
  1122.     int    paperr,
  1123.         wcomp,
  1124.         num_bytes,
  1125.         count,
  1126.         index;
  1127.  
  1128.     if (line != NULL)
  1129.     {
  1130.         c = line;
  1131.         for(index = 0; index <line_len; index++)
  1132.             if(*(c+index) == '\004')
  1133.                 *(c+index) = '\n';
  1134.         pap_write(sock,line,line_len,FALSE);
  1135.     }
  1136.     do
  1137.     {
  1138.         if (r_eof == 1)
  1139.             break;
  1140.         num_bytes = read(fileno(stdin),buff,BUF_SIZ - 1);
  1141. #ifdef    DEBUG
  1142.         fprintf(stderr,"Num_Bytes in read = %d\n", num_bytes);
  1143. #endif    DEBUG
  1144.         c = buff;
  1145.         index = 0;
  1146.         count = 0;
  1147.         while(count < num_bytes)
  1148.         {
  1149.             index++;
  1150.             count++;
  1151.             if (*(c+index) == '\004')
  1152.             {
  1153.                 *(c+index) = '\n';
  1154.                 pap_write(sock,c,index,TRUE);
  1155.                 abSleep(4,TRUE);
  1156.                 c += index;
  1157.                 index = 0;
  1158.                 PAPClose(sock);
  1159.                 sock = connect_to_laser(atalk_name);
  1160.                 r_comp = 0;
  1161.                 r_eof = 0;
  1162.                 r_err = 0;
  1163.             }
  1164.         }
  1165.         pap_write(sock,c,index,FALSE);
  1166.         abSleep(4,TRUE);
  1167.     }while (num_bytes != 0);
  1168.     if (r_eof == 0)
  1169.     {
  1170.         pap_write(sock,c,0,TRUE);
  1171.         pap_read(sock);
  1172.     }
  1173.     abSleep(2,TRUE);
  1174. }
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182. /**************************************************************************
  1183.  *  Initialise the appletalk libraries (CAP), form the connection to the
  1184.  *  LaserWriter and process the data stream.  Log the job to the printer
  1185.  *  log file.
  1186.  */
  1187.  
  1188.  
  1189.  
  1190. /* ARGS USED */
  1191.  
  1192. main(argc,argv)
  1193.     int    argc;
  1194.     char    *argv[];
  1195. {
  1196.  
  1197.     char    stat_string[80];
  1198.  
  1199.     check_args(argc,argv);
  1200.     load_config();
  1201.     set_sigs();
  1202.     atalk_name = find_lasername(printer);
  1203.     if (atalk_name == NULL)
  1204.         syslog(LOG_ERR,"PC-PAP : Could not map %s to a printer name",
  1205.             printer);
  1206.     abInit(FALSE);
  1207.     nbpInit();
  1208.     PAPInit();
  1209.     ATPSetResponseTimeout(sectotick(60));         /* 1 Minutes */
  1210.     sock = connect_to_laser(atalk_name);
  1211.     process_file(sock);
  1212.     abSleep(4,TRUE);
  1213.     PAPClose(sock);
  1214.     sprintf(stat_string,"%s : No Status  (No Active Jobs)",printer);
  1215.     write_status(stat_string);
  1216. }
  1217. \End\Of\Shar\
  1218. else
  1219.   echo "will not over write ./pc-pap.c"
  1220. fi
  1221. if `test ! -s ./pc-pap.conf.example`
  1222. then
  1223. echo "writing ./pc-pap.conf.example"
  1224. cat > ./pc-pap.conf.example << '\End\Of\Shar\'
  1225. #      @(#)/usr/local/lib/pc-pap.conf  (Bond)   
  1226. #
  1227. # Language configuration file for PC-PAP   31-Jan-1991    bambi@kirk.bu.oz.au
  1228. #
  1229. #    Definitions of language recognition tokens, output filters and
  1230. #    PostScript magics.
  1231. #
  1232. #     There are four sections to the configuration :- postscript, text,
  1233. #    filters and magics.  The start of a section is defined by the
  1234. #    section name preceded by a + on a line by itself.
  1235. #
  1236. #    In the postscript section, the only entries are character tokens
  1237. #    that define the start of a PostScript file.  The tokens are terminated
  1238. #    by a colon.
  1239. #
  1240. #    The text section contains one definition being the path, name, and
  1241. #    commandline options for a text to PostScript filter.  Each field is
  1242. #    colon separated.  Up to ten command line options may be defined
  1243. #    to represent argv[1] through argv[9] (argv[0] is set to the
  1244. #    filter name.
  1245. #    
  1246. #    The filters section contains a list of filters used in pc-pap to 
  1247. #    convert a certain language into PostScript.  The format of an entry is
  1248. #    <ID>:<Path to filter>:<Name of filter>:<Arg1>:<Arg2>:<Arg N>:
  1249. #
  1250. #    The final section, magics, contains the token to filter matchings
  1251. #    for the language translations.  The format of an entry is
  1252. #    <Filter ID>:<Magic Token>:
  1253. #
  1254. #    NOTE: The token must appear at the start of the first line of the file
  1255. #          if it is to be recognised.  The \ character is the standard
  1256. #             escape and may be followed by any 3 digit decimal ASCII 
  1257. #          code (such as \004 for ^D or \058 for :).
  1258. #
  1259. #    What appears below is a sample setup used on a host at Bond Uni.
  1260. #
  1261.  
  1262. +postscript
  1263.  
  1264. %!:
  1265. \004%!:
  1266.  
  1267. +text
  1268.  
  1269. /usr/local/lib/translators/t2ps:t2ps::
  1270.  
  1271. +filters
  1272.  
  1273. C_PS:/usr/local/lib/translators/pps:pps:c:
  1274. sh_PS:/usr/local/lib/translators/pps:pps:sh:
  1275. csh_PS:/usr/local/lib/translators/pps:pps:csh:
  1276. mail_PS:/usr/local/lib/translators/mp:mp::
  1277.  
  1278. +magics
  1279.  
  1280. C_PS:/*:
  1281. C_PS:#include<:
  1282. C_PS:#include <:
  1283. C_PS:static:
  1284. C_PS:#ifdef:
  1285.  
  1286. sh_PS:#!/bin/sh:
  1287. sh_PS:#! /bin/sh:
  1288.  
  1289. csh_PS:#!/bin/csh:
  1290. csh_PS:#! /bin/csh:
  1291.  
  1292. mail_PS:From :
  1293. mail_PS:From\58:
  1294. mail_PS:Path\58:
  1295.  
  1296. \End\Of\Shar\
  1297. else
  1298.   echo "will not over write ./pc-pap.conf.example"
  1299. fi
  1300. if `test ! -s ./pc-pap.h`
  1301. then
  1302. echo "writing ./pc-pap.h"
  1303. cat > ./pc-pap.h << '\End\Of\Shar\'
  1304. /*
  1305.  *        Title    : PC-PAP.h
  1306.  *        Author    : David J. Highes    bambi@kowande.bu.oz.au
  1307.  *        Date    : 14-June-1990
  1308.  *        Dept    : Network Management Group
  1309.  *              Bond University
  1310.  */
  1311.  
  1312. #define CAP_PRINTERS    "/etc/cap.printers"     /* Location of CAP file */
  1313. #define conf_dir        "/usr/local/lib"    /* Directory of config file */
  1314. #define conf_file       "pc-pap.conf"        /* Config file name */
  1315. #define lang_len        10            /* Max length of lang ID */
  1316. #define path_len        80            /* Max length of filter path */
  1317. #define name_len        10            /* Max length of filter name */
  1318. #define args_len        20            /* Max length of filter args */
  1319. #define magic_len       30            /* Max length of magic tokens */
  1320. #define    num_filter_args    10            /* Max number args to filter */
  1321. #define STATUS          5                       /* Check Status interval (sec)*/
  1322. #define QUANTUM         8                       /* PAP Flow Quantum */
  1323. #define PS_CHILD        1            /* Debug */
  1324. #define FILTER_CHILD    2            /*       Procedure */
  1325. #define READ_CHILD      3                       /*                 Flags */
  1326. #define TEXT_PS     "text_PS"
  1327. #define    LPD_OK        0            /* LPD Good Print Exit Code */
  1328. #define LPD_REPRINT     1                /* LPD Reprint Exit Code */
  1329. #define    LPD_ERROR    2            /* LPD Abort Job Exit Code */
  1330.  
  1331.  
  1332. typedef struct  token_s
  1333. {
  1334.         char    token[magic_len];
  1335.         char    lang[lang_len];
  1336. } token_t;
  1337.  
  1338.  
  1339. typedef struct  filter_s
  1340. {
  1341.         char    lang[lang_len];
  1342.         char    path[path_len];
  1343.         char    name[name_len];
  1344.         char    args[10][args_len];
  1345. } filter_t;
  1346.  
  1347.  
  1348. \End\Of\Shar\
  1349. else
  1350.   echo "will not over write ./pc-pap.h"
  1351. fi
  1352. echo "Finished archive 1 of 1"
  1353. exit
  1354.  
  1355.  
  1356.