/* * LPR - dump job to printer * * * Copyright (C) 1991, University of Waterloo * * Portions Copyright (C) 1990, National Center for Supercomputer Applications * and portions copyright (c) 1990, Clarkson University * * This program is free software; you can redistribute it and/or modify * it, but you may not sell it. * * This program is distributed in the hope that it will be useful, * but without any warranty; without even the implied warranty of * merchantability or fitness for a particular purpose. * * Erick Engelke or via E-Mail * Faculty of Engineering * University of Waterloo Erick@development.watstar.uwaterloo.ca * 200 University Ave., * Waterloo, Ont., Canada * N2L 3G1 * * * The following notes on control and data files were obtained from Clarkson's * CUTE project. * * * Control File: format is the first character in the line is a command, * the rest of the line is the argument. Also note lowercase letters * denote the data file names (of various types). * * currently valid commands are: * * J -- "job name" on banner page * C -- "class name" on banner page * L -- "literal" user's name to print on banner * T -- "title" for pr * H -- "host name" of machine where lpr was done * P -- "person" user's login name * I -- "indent" amount to indent output * f -- "file name" name of text file to print * l -- "file name" text file with control chars * p -- "file name" text file to print with pr(1) * t -- "file name" troff(1) file to print * n -- "file name" ditroff(1) file to print * d -- "file name" dvi file to print * g -- "file name" plot(1G) file to print * v -- "file name" plain raster file to print (impress) * c -- "file name" cifplot file to print * 1 -- "R font file" for troff * 2 -- "I font file" for troff * 3 -- "B font file" for troff * 4 -- "S font file" for troff * N -- "name" of file (used by lpq) * U -- "unlink" name of file to remove * (after we print it. (Pass 2 only)). * M -- "mail" to user when done printing * * Currently it looks like only a lowercase filename and U command are * necessary. However one should also include J, L, H, and P. * * In general the lpd program doesn't care what the data file looks like. * It should however be of the type specified in the control file * otherwise it will probably print incorrectly. * * The format is ?fA. ? is either c for control or d * for data files. Number is a 3 digit number (0 padded) used for job * number information. Hostname is the name of the originating host and * had best be equal to whatever shows up in the from field when a * connection is opened (ie probably should be the "real" hostname). * Currently all of these must be used as the program has them compiled in * (by stupid use of pointers). I may change this in time but currently * it is the law if you want everything to work (some things will work * just fine without it, queueing a file just wants names, showing the * queue expects a number to start in the fourth position, deleting a file * expects the hostname to start in the 7th position and go to the end of * the filename. */ #include #include #include #define SHORT_LIST 3 #define LONG_LIST 4 #define LPQ_PORT 515 #define LOCAL_PORT 722 lpr( localhostname, printer, rhostname, filename, username, servername ) char *localhostname; char *printer; char *rhostname; char *filename; char *username; char *servername; { tcp_Socket socketdata, *s; longword filesize; longword host; int status = 0; int connected = 0; int localport; int len; longword curtime; char buffer[ 1024 ]; char remotename[ 80 ]; char cmdfile[ 1024 ]; longword remaining, found, bufsize; FILE *f; /* */ /* Quick and dirty arg stuff. This needs to be done right */ if (!(f = fopen( filename, "rb"))) { printf("Unable to open file '%s'\n", filename ); return( 3 ); } sock_init(); s = &socketdata; if (!(host = resolve( rhostname ))) { fprintf(stderr, "lpq: unknown host %s\n",rhostname); return(1); } localport = 255 + (MsecClock() & 255); if ( !tcp_open( s, localport, host, LPQ_PORT, NULL)) { fprintf(stderr,"Unable to open socket."); tcp_shutdown(); return(1); } fprintf( stdout, "connecting...\r"); sock_wait_established( s, sock_delay, NULL, &status ); connected = 1; fprintf(stdout,"connection established"); /* is there an opening message - non-standard but possible */ if (sock_dataready( s )) { sock_fastread( s, buffer, sizeof( buffer )); sock_tick( s, &status ); /* in case above message closed port */ } /* use ipnumber/time */ time( &curtime ); sprintf(remotename,"fA.%8lx.%8lx", my_ip_addr ,curtime); /* we are connected */ sprintf( buffer, "\2%s\n", printer ); /* select a printer */ sock_puts( s, buffer ); /* state #2 */ sock_wait_input( s, sock_delay, NULL, &status ); sock_fastread( s, buffer, sizeof( buffer )); switch (*buffer) { case 0 : break; case 1 : printf("Printer '%s' is not available\n", printer); goto close_it; default: puts("Some unknown error encounterred"); goto close_it; } /* printer is accepted, printing file */ filesize = filelength( fileno( f )); sprintf( buffer, "\3%ld d%s\n", filesize, remotename ); sock_puts( s , buffer ); sock_wait_input( s, sock_delay, NULL, &status ); /* state 3, reply from filename */ sock_fastread( s, buffer, sizeof( buffer )); switch (*buffer) { case 0: break; case 1: fprintf(stderr,"remote host complains of bad connection"); goto close_it; case 2: puts("remote host out of storage space"); goto close_it; } /* dump file */ remaining = filesize; bufsize = sizeof( buffer ); do { if (remaining < bufsize ) bufsize = remaining; if (!(found = fread( buffer, 1, sizeof(buffer), f))) break; sock_write( s, buffer, found ); sock_tick( s , &status ); if (sock_dataready( s )) { puts("LPR: interrupted on transfer..."); goto close_it; break; } } while ( (remaining -= found) > 0 ); sock_putc( s, 0 ); /* check on status of this file */ sock_wait_input( s, sock_delay, NULL, &status ); sock_fastread( s, buffer, sizeof(buffer)); switch (*buffer) { case 0: break; default:puts("file was rejected"); goto close_it; /* could retry */ } sprintf( cmdfile, "H%s\n" "P%s\n" "C%s\n" "G%s\n" "L%s\n" "T%s\n" "fd%s\n" "N%s\n" "Ud%s\n" "J%s\n", localhostname, /* eg "maggot.watstar" */ username, /* eg "erick", */ servername, /* eg "development", */ "nobody", /* group */ username, /* eg "erick", for on banner */ "SomeJobTitle", /* title */ remotename, /* file processor */ "local_name", remotename, "Job_name" ); remotename[1] ^= 1; sprintf( buffer, "\2%d c%s\n", strlen( cmdfile ), remotename ); sock_puts( s , buffer ); sock_flush( s ); sock_wait_input( s, sock_delay, NULL, &status ); sock_fastread( s, buffer, sizeof( buffer )); switch (*buffer) { case 0: break; case 1: puts("Bad connection"); goto close_it; case 2: puts("Out of space on host"); goto close_it; default:puts("Unknown error"); goto close_it; } sock_puts( s, cmdfile ); sock_putc( s, 0 ); sock_flush( s ); sock_wait_input( s, sock_delay, NULL, &status ); sock_fastread( s, buffer, sizeof( buffer )); switch (*buffer) { case 0: puts("Complete"); sock_putc( s, 0 ); sock_flush( s ); break; default:puts("Control file rejected"); status = 3; break; } /* all roads come here */ close_it: sock_tick( s, &status); /* in case they sent reset */ sock_close( s ); sock_wait_closed( s, sock_delay, NULL, &status ); sock_err: switch( status ) { case 1: break; case-1: fprintf(stderr,"Remote host reset connection\n\r"); status = 3; break; } if (!connected) fprintf( stdout, "\n\rCould not get connected. Perhaps you were not in the /etc/hosts.lpd file!\n\r"); return( status ); } main(argc, argv) int argc; char **argv; { char remotename[128]; char *filename; char *printer; char *userid, *server; char *rhostname; int status; userid = server = "UNKNOWN"; puts("LPR using Waterloo TCP"); switch (argc) { case 3: /* no printername */ rhostname = argv[1]; filename = argv[2]; printer = "lp"; break; case 6: /* whole thing */ userid = argv[4]; server = argv[5]; /* and continue on below */ case 4: /* Hostname and printer */ printer = argv[1]; rhostname = argv[2]; filename = argv[3]; break; default: fprintf(stdout, "Usage: LPR [printer] host filename [userid server]"); exit(1); } status = lpr( "maggot", printer, rhostname, filename, userid, server ); return( status ); }