/* lpf.lj4m.c -- Michael A. Covington, 1993 July 6 Pre-spooler filter for LaserJet 4M. Install with the "if=" (NOT "of=") option in /etc/printcap. Examines first 2 bytes of each file to classify it as HP printer code, PostScript, or ASCII. Then does the following: - Transmits HP printer code transparently. (Must begin with Esc E.) - Transmits PostScript code transparently, adding Ctrl-D at the end. - Transmits ASCII code thus: + Adds printer setup (font selection, etc.) at beginning; + Adds a blank at the beginning of each line (so the 4M won't mistake Prolog programs for PostScript); + Breaks lines more than 80 characters long; + Aborts if the file contains unprintable bytes. Install with the "if=" (NOT "of=") option in printcap. Print jobs are logged in /var/adm/lpd-errs. BUG: Does not produce correct results on jobs shorter than 2 bytes. But who would print such a file anyhow? (Famous last words...) This program can be tested under other operating systems because the UNIX-specific parts are subject to "#ifdef UNIX". */ #define UNIX 1 #ifdef UNIX #include #endif #include #include #define CTRLD "\004" #define SPACES " " /* prepended to every ASCII line */ #define LINELENGTH 80 /* HP LaserJet control sequences */ #define RESET "\033E" #define LF_TO_CRLF "\033&k2G" #define LMARGIN "\033&a11L" #define PORTRAIT "\033&l0O" #define ASCII "\033(8U" #define FONT "\033(s0p(s12h(s4099T" #define LOWERTRAY "\033&l1H" /* Globals */ int c1, c2; long int bytes = 1; char username[64] = ""; #define PRINTABLE(c) (Printable[(unsigned char)c]) char Printable[256] = /* Table of which ASCII codes are printable characters */ { 0,0,0,0,1,0,0,1,1,1,1,0,1,1,0,0, /* NUL to ^O */ 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, /* ^P to 31 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 32 to 47 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 48 to 63 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 64 to 79 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 to 95 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 96 to 112 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, /* 113 to 127 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128 to 143 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144 to 159 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160 to 175 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176 to 191 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192 to 207 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208 to 223 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224 to 239 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }; /* 240 to 255 */ /* -1 (eof) maps onto 255 */ /************ FUNCTIONS *************/ void parse_user_name(int argc, char* argv[]){ /* * Obtain user name if it was passed to the program */ if (argc>8) { strcat(username,argv[5]); strcat(username,"@"); strcat(username,argv[7]); } } void process_postscript(){ /* * Transmit PostScript file transparently to stdout */ #ifdef DEBUG fprintf(stderr,"lpf.lj4m: %s: File treated as PostScript\n",username); #endif putc(c1,stdout); while(!feof(stdin)) { bytes++; putc(c2,stdout); c2 = getc(stdin); } /* * Add newline and Ctrl-D at end */ fputs("\n"CTRLD,stdout); /* * Report results */ #ifdef UNIX syslog(LOG_DEBUG,"%s, PostScript file, %d bytes",username,bytes); #endif #ifdef DEBUG fprintf("lpf.lj4m: %s: End of PostScript job\n",username); #endif } void process_hp(){ /* * Transmit Hewlett-Packard code transparently, then reset printer */ #ifdef DEBUG fprintf(stderr,"lpf.lj4m: %s: File treated as HP LaserJet code\n",username); #endif putc(c1,stdout); while(!feof(stdin)) { bytes++; putc(c2,stdout); c2 = getc(stdin); } /* * Add Reset at end */ fputs(RESET,stdout); /* * Report results */ #ifdef DEBUG fprintf(stderr,"lpf.lj4m: %s: End of LaserJet job\n",username); #endif #ifdef UNIX syslog(LOG_DEBUG,"%s, LaserJet file, %d bytes",username,bytes); #endif } void process_ascii(){ int charcount = 0, ok_to_print; int k = 0; /* * Initialization */ #ifdef DEBUG fprintf(stderr,"lpf.lj4m: %s: File treated as ASCII text\n",username); #endif /* * Set up printer */ fputs(RESET,stdout); fputs(LF_TO_CRLF,stdout); fputs(FONT,stdout); fputs(LMARGIN,stdout); /* * Transmit file, prepending ' ' to each line, * and breaking lines that exceed 80 characters <-- to do * and bailing out if unprintable bytes are found */ ok_to_print = PRINTABLE(c1) && PRINTABLE(c2); fputs(SPACES,stdout); if (ok_to_print) putc(c1,stdout); while(ok_to_print && !feof(stdin)) { bytes++; if ((charcount >= LINELENGTH) && (c2 != '\n')) { fputs("\n"SPACES,stdout); /* start new line, indented, if needed */ charcount = 0; } if ((c2 != 4) && (c2 != 26)) { /* whatever the character */ putc(c2,stdout); /* print if not ^D, ^Z */ charcount++; } if (c2 == '\n') { /* if end of line */ fputs(SPACES,stdout); /* indent next line */ charcount = 0; } c2 = getc(stdin); ok_to_print = PRINTABLE(c2); } /* * If a bad byte was found, print messages: */ if(!ok_to_print){ /* * Set up printer again, because it may have been disrupted */ fputs("\n",stdout); fputs(RESET,stdout); fputs(LF_TO_CRLF,stdout); fputs(FONT,stdout); fputs(LMARGIN,stdout); /* * Message in the printout itself */ fprintf(stdout," ERROR\n\n Print job for %s\n\n",username); fprintf(stdout," Unprintable character, code %d, location %d\n\n",c2,bytes); fprintf(stdout," The print filter assumed that this file was ASCII text,\n"); fprintf(stdout," but found an unprintable character in it.\n\n"); fprintf(stdout," Here is a portion of the file:"); /* * Partial dump of file */ while((k<80*30) && (!feof(stdin))) { if (k % 80 == 0) fputs("\n"SPACES,stdout); if ((c2 >= 32) && (c2 <= 126)) putc(c2,stdout); else putc('.',stdout); c2 = getc(stdin); k++; } /* * Message to console */ fprintf(stderr,"lpf.lj4m: %s: tried to print an unprintable file\n",username); /* * Message to system logs */ #ifdef UNIX syslog(LOG_ERR,"lpf.lj4m: %s: tried to print an unprintable file\n",username); #endif } /* * Reset printer at end */ fprintf(stdout,"%s",RESET); /* * Report results */ #ifdef DEBUG fprintf(stderr,"lpf.lj4m: %s: End of ASCII job\n",username); #endif #ifdef UNIX syslog(LOG_DEBUG,"%s, ASCII file, %d bytes",username,bytes); #endif } /************** MAIN ****************/ main(int argc, char* argv[]){ /* * Initialization */ parse_user_name(argc,argv); #ifdef UNIX openlog("LaserJet",0,LOG_LPR); #endif /* * Examine first 2 bytes and determine type of file */ c1 = getc(stdin); c2 = getc(stdin); if ( (c1 == '%') && (c2 == '!') ) process_postscript(); else if ( (c1 == 27) && (c2 == 'E') ) process_hp(); else process_ascii(); #ifdef UNIX closelog(); #endif return(0); /* IMPORTANT! UNIX insists on this.*/ }