home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2755 < prev    next >
Internet Message Format  |  1991-02-13  |  32KB

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