/* * $Header: xnsprint.c,v 2.4 87/01/09 16:34:23 ed Exp $ * * a program to print InterPress masters on an InterPress printer via * Ethernet. Uses xns Courier. * This version runs on 4.3BSD only! */ /* * $Log: xnsprint.c,v $ * Revision 2.4 87/01/09 16:34:23 ed * Webster version * * Revision 2.4 87/01/09 16:34:23 ed * Added -W flag to wait until printing is completed (from Lee Moore) * * Revision 2.3 86/12/11 04:43:34 jqj * Added support for -s and -m flags. * * Revision 2.2 86/09/07 06:57:41 jqj * Fixed inconsistent calls to attnmsg() by eliminating stderr first arg. * Changed banner not to use "Cornell Computer Science". * * Revision 2.1 86/05/16 11:04:18 jqj * fix to correspond to new enumeration semantics (tags are now global) * * Revision 2.0 85/11/21 07:23:11 jqj * 4.3BSD standard release * * Revision 1.1 85/11/20 13:56:53 jqj * Initial revision * * modified 8-6-85 by jqj. * Eliminated any hardwired addresses. Instead, use CH_Enumerate to * find a printer if none is specified. Also, you can now print multiple * files in a single call to xnsprint, and getopt() is used to parse * arguments. */ #include <stdio.h> #include <sys/types.h> #include <netns/ns.h> #include <netns/sp.h> #include "Printing3_defs.h" #include <xnscourier/Clearinghouse2.h> #include <xnscourier/except.h> #include <pwd.h> #include <sys/file.h> #include <strings.h> static FILE *ipfile = NULL; static int ExitStatus = 0; /* modified lpd conventions: */ /* 0 => Job printed. (successfully sent to print-server) */ #define X_GOOD 0 /* 1 => Couldn't send job. Retry forever, should go eventually. */ #define X_RETRY 1 /* 2 => Couldn't send job, Strange error, Retry a limited number*/ /* of times. If it still hasn't worked, give up. */ #define X_LIMRETRY 2 /* 3 => Couldn't send job: Hard error, don't bother retrying, */ /* get rid of the job. */ #define X_NORETRY 3 static struct { char * sizename; int sizevalue; } papersizetable[] = { "usLetter", (int) usLetter, /* 1 */ "usLegal", (int) usLegal, /* 2 */ "a0", (int) a0, /* 3 */ "a1", (int) a1, /* 4 */ "a2", (int) a2, /* 5 */ "a3", (int) a3, /* 6 */ "a4", (int) a4, /* 7 */ "a5", (int) a5, /* 8 */ "a6", (int) a6, /* 9 */ "a7", (int) a7, /* 10 */ "a8", (int) a8, /* 11 */ "a9", (int) a9, /* 12 */ "a10", (int) a10, /* 35 */ "isoB0", (int) isoB0, /* 13 */ "isoB1", (int) isoB1, /* 14 */ "isoB2", (int) isoB2, /* 15 */ "isoB3", (int) isoB3, /* 16 */ "isoB4", (int) isoB4, /* 17 */ "isoB5", (int) isoB5, /* 18 */ "isoB6", (int) isoB6, /* 19 */ "isoB7", (int) isoB7, /* 20 */ "isoB8", (int) isoB8, /* 21 */ "isoB9", (int) isoB9, /* 22 */ "isoB10", (int) isoB10, /* 23 */ "jisB0", (int) jisB0, /* 24 */ "jisB1", (int) jisB1, /* 25 */ "jisB2", (int) jisB2, /* 26 */ "jisB3", (int) jisB3, /* 27 */ "jisB4", (int) jisB4, /* 28 */ "jisB5", (int) jisB5, /* 29 */ "jisB6", (int) jisB6, /* 30 */ "jisB7", (int) jisB7, /* 31 */ "jisB8", (int) jisB8, /* 32 */ "jisB9", (int) jisB9, /* 33 */ "jisB10", (int) jisB10, /* 34 */ (char *) 0, 0 }; SendSource(bdtconnection) CourierConnection *bdtconnection; { int count; char buffer[SPPMAXDATA]; while ( (count = fread(buffer,1,SPPMAXDATA,ipfile)) > 0 && BDTwrite(bdtconnection,buffer,count) >= 0 ) ; if (count <= 0) BDTclosewrite(bdtconnection); /* last packet with EOM set */ else BDTabort(bdtconnection); } /* * misc externals */ int remove = 0; int quiet = 0; int attn = 0; /* Write lpr system STATUS file? LCP 850415*/ char *attnfile; /* Status file name. LCP 850415 */ char *FileName = NULL; char *UserName = NULL; char *Banner = NULL; int copies = 1; Medium paperchoice; char *UserMessage = NULL; Clearinghouse2_Name hostname; char *xnshost = NULL; int WaitFlag = 0; /* wait until job is printed ? LCM */ setxnshost(name) Clearinghouse2_ObjectName name; { extern char *malloc(), *strcpy(); if (xnshost == NULL) xnshost = strcpy(malloc(strlen(name.object)+1),name.object); } main(argc, argv) int argc; char **argv; { struct ns_addr *destaddr; CourierConnection *conn; extern struct ns_addr *getXNSaddr(); extern struct ns_addr *CH_LookupAddr(); Clearinghouse2_Name defaultname; extern Clearinghouse2_Name CH_StringToName(); int opt; extern int optind; extern char *optarg; int errflg = 0; int i; paperchoice.designator = paper; paperchoice.paper_case.designator = knownSize; paperchoice.paper_case.knownSize_case = usLetter; while ((opt = getopt(argc,argv,"c:n:b:P:h:rqa:lm:s:W")) != EOF) switch (opt) { case 'c': /* copies */ copies = atoi(optarg); break; case 'n': /* user name */ UserName = optarg; break; case 'b': /* file name */ Banner = optarg; break; case 'P': /* printer */ case 'h': /* host */ xnshost = optarg; break; case 'r': /* remove input file when done */ remove++; break; case 'q': /* don't print status messages */ quiet++; break; case 'a': /* Write lpr STATUS file. Name follows. LCP 850415 */ quiet++; attn++; attnfile = optarg; break; case 'l': /* use legal-sized (long) paper */ paperchoice.paper_case.knownSize_case = usLegal; break; case 'm': /* message field follows (default to XNS name) */ UserMessage = optarg; break; case 's': /* papersize name follows */ for (i = 0; papersizetable[i].sizename != NULL; i++) if (strcmp(optarg,papersizetable[i].sizename) == 0) { *(int*)& paperchoice.paper_case.knownSize_case = papersizetable[i].sizevalue; goto gotsize; } *(int*)& paperchoice.paper_case.knownSize_case = atoi(optarg); gotsize: break; case 'W': /* wait for the job to be printed LCM */ WaitFlag++; break; default: errflg = 1; } if (errflg) { attnmsg("Usage: %s [-r] [-P host] [-c #] [-n name] [-b banner] [-l] [-s size] [-m message] [-W] file...\n", argv[0]); exit(X_NORETRY); } /* set User Name for banner if necessary */ if (UserName == NULL) { struct passwd *pwd, *getpwuid(); char *p; extern char *getenv(), *index(); UserName = getenv("USER"); if ((pwd = getpwuid(getuid())) != NULL) { UserName = pwd->pw_gecos; if (p = index(UserName,',')) *p = '\000'; } } /* figure out what address we're sending to */ CH_NameDefault(&defaultname);/* default from clearinghouse.addresses */ if (xnshost == NULL) { xnshost= getenv("PRINTER"); if ( (xnshost == NULL) || (*xnshost == '\0') ) { /* find the first object in the local domain of the CH * with a printService property. setxnshost sets xnshost * to the name part of the object */ hostname = defaultname; hostname.object = "*"; CH_Enumerate(hostname,10001,setxnshost); hostname.object = xnshost; } else hostname = CH_StringToName(xnshost,&defaultname); } else hostname = CH_StringToName(xnshost,&defaultname); if ((destaddr = CH_LookupAddr(hostname,4)) == NULL) { attnmsg("Invalid address, %s:%s:%s\n", hostname.object,hostname.domain,hostname.organization); exit(X_NORETRY); } /* make sure the printer is available */ checkIPstatus(destaddr); for ( ; optind < argc; optind++) { FileName = argv[optind]; if (strcmp(FileName,"-") == 0) { ipfile = stdin; FileName = "standard input"; } else if ((ipfile = fopen(FileName,"r")) == NULL) { fprintf(stderr, "%s: Can't open %s\n", argv[0], FileName); exit(X_NORETRY); } if(Banner == NULL) Banner = FileName; if (!quiet) printf("Sending to %s...", xnshost); fflush(stdout); sendIPfile(ipfile,destaddr); if (ipfile != stdin) fclose(ipfile); } if (!quiet) printf("Done.\n"); exit(X_GOOD); } /* * Check printer status first so we won't dump big interpress * files accross the net unless we're fairly confidant that they'll * be accepted. */ checkIPstatus(destaddr) struct ns_addr *destaddr; { CourierConnection *conn; GetPrinterStatusResults StatusResult; do { if (!quiet) printf("Opening connection to %s. ",xnshost); if (attn) attnmsg("Opening connection to %s.\n",xnshost); if ((conn = CourierOpen(destaddr)) == NULL) { attnmsg("Can't open connection to %s\n",xnshost); if(remove && !attn) attnmsg("Output left in %s\n", FileName); exit(X_LIMRETRY); } if (!quiet) printf("Connected.\n"); if (attn) attnmsg("Requesting status.\n"); DURING StatusResult = GetPrinterStatus(conn,NULL); HANDLER { ExitStatus = X_LIMRETRY; switch (Exception.Code) { case ServiceUnavailable: attnmsg("GetStat: Service unavailable\n"); ExitStatus = X_NORETRY; break; case SystemError: attnmsg("GetStat: System Error\n"); break; case Undefined: attnmsg("GetStat: Undefined error, number %d\n", CourierErrArgs(UndefinedArgs,problem)); break; case REJECT_ERROR: attnmsg("GetStat: REJECT: type = %d\n", CourierErrArgs(rejectionDetails, designator)); break; default: attnmsg("GetStat: Some random error, code %d\n", Exception.Code); break; } if (remove && !attn) attnmsg("Output left in %s\n", FileName); exit(ExitStatus); } END_HANDLER; CourierClose(conn); } while (printresults(StatusResult.status) != 0); } /* * display printer status, return 0 IFF spooler is available */ int printresults(status) PrinterStatus status; { int i, typ; static char *spoollist[] = {"available","busy","disabled","full"}; static char *formatlist[] = {"available","busy","disabled"}; static char *printlist[] = {"available","busy","disabled", "needs attention","needs key operator"}; int error = 1; char bufr[256]; bufr[0] = '\0'; for (i = 0; i < status.length; i++) { switch (status.sequence[i].designator) { case spooler: typ = (int) status.sequence[i].spooler_case; if (!quiet || typ > 1) sprintf(bufr+strlen(bufr), "Spooler: %s; ", spoollist[typ]); error = typ; break; case formatter: typ = (int) status.sequence[i].formatter_case; if (!quiet || typ > 1) sprintf(bufr+strlen(bufr), "Formatter: %s; ", formatlist[typ]); break; case printer: typ = (int) status.sequence[i].printer_case; if (!quiet || typ > 1) sprintf(bufr+strlen(bufr), "Printer: %s. ", printlist[typ]); break; case media: /* printmedia(status.sequence[i].media_case); */ break; } } if (bufr[0] != '\0') { if (attn) attnmsg("%s\n",bufr); else printf("%s\n",bufr); } switch(error) { case 0: break; case 1: if (!quiet) printf("Retrying... "); if (bufr[0] != '\0' && attn) attnmsg("Status: Busy. Retrying...\n"); fflush(stdout); sleep(15); break; default: if(remove && !attn) attnmsg( "Output left in %s\n", FileName); exit(1); } return(error); } attnmsg(fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9) char *fmt; { char bufr[256]; int af; if (attn) { if ((af = open(attnfile,O_TRUNC|O_WRONLY|O_CREAT,0666)) < 0) return; /* Oh Well. */ sprintf(bufr,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9); (void) write(af,bufr,strlen(bufr)); /* In case of error??? */ close(af); } else fprintf(stderr,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9); } sendIPfile(ipfile,destaddr) FILE *ipfile; struct ns_addr *destaddr; { PrintResults result; CourierConnection *conn; PrintAttributes attributes; PrintOptions options; char *malloc(); /* only use sender name and file name, no date */ attributes.length = 2; attributes.sequence = malloc(attributes.length * sizeof(*attributes.sequence)); attributes.sequence[0].designator = printObjectName; attributes.sequence[0].printObjectName_case = Banner; attributes.sequence[1].designator = senderName; attributes.sequence[1].senderName_case = UserName; options.length = 3; options.sequence = malloc(options.length * sizeof(*options.sequence)); options.sequence[0].designator = copyCount; options.sequence[0].copyCount_case = copies; options.sequence[1].designator = mediumHint; options.sequence[1].mediumHint_case = paperchoice; options.sequence[2].designator = message; options.sequence[2].message_case = UserMessage ? UserMessage : sprintf(malloc(44),"%s:%s:%s", hostname.object,hostname.domain, hostname.organization) ; again: if (!quiet) printf("Opening connection to %s. ",xnshost); if (attn) attnmsg("Opening connection to %s.\n",xnshost); if ((conn = CourierOpen(destaddr)) == NULL) { attnmsg("Can't open connection to %s\n",xnshost); if(remove && !attn) attnmsg("Output left in %s\n", FileName); exit(X_LIMRETRY); } if (!quiet) printf("Connected.\n"); if (attn) attnmsg("Sending to %s\n",xnshost); DURING result = Print(conn, SendSource, BulkData1_immediateSource, attributes, options); HANDLER { ExitStatus = X_RETRY; switch (Exception.Code) { case Busy: if (!quiet) printf("Busy, retrying...\n"); if (attn) attnmsg("Busy, retrying...\n"); CourierClose(conn); sleep(15); if (rewind(ipfile) < 0) { ExitStatus = X_LIMRETRY; attnmsg("Can't rewind file\n"); } goto again; case ConnectionError: ExitStatus = X_LIMRETRY; attnmsg("Connection error, %d\n", CourierErrArgs(ConnectionErrorArgs,problem)); break; case InsufficientSpoolSpace: attnmsg("Insufficient Spool Space error\n"); break; case InvalidPrintParameters: ExitStatus = X_LIMRETRY; attnmsg("InvalidPrintParameters error\n"); break; case MasterTooLarge: ExitStatus=X_NORETRY; attnmsg("MasterTooLarge error\n"); break; case MediumUnavailable: ExitStatus=X_NORETRY; attnmsg("MediumUnavailable error\n"); break; case ServiceUnavailable: ExitStatus=X_NORETRY; attnmsg("ServiceUnavailable error\n"); break; case SpoolingDisabled: attnmsg("SpoolingDisabled\n"); break; case SpoolingQueueFull: attnmsg("SpoolingQueueFull error\n"); break; case SystemError: ExitStatus = X_LIMRETRY; attnmsg("System Error\n"); break; case TooManyClients: attnmsg("TooManyClients error\n"); break; case TransferError: ExitStatus = X_LIMRETRY; attnmsg("TransferError error\n"); break; case Undefined: attnmsg("Undefined error, number %d\n", CourierErrArgs(UndefinedArgs,problem)); break; case REJECT_ERROR: ExitStatus = X_LIMRETRY; attnmsg("REJECT: type = %d\n", CourierErrArgs(rejectionDetails, designator)); break; default: ExitStatus = X_LIMRETRY; attnmsg("Some random error, code %d\n", Exception.Code); break; } if(remove && !attn) attnmsg("Output left in %s\n", FileName); exit(ExitStatus); } END_HANDLER; if (WaitFlag) /* wait for completion LCM */ WaitForCompletion(conn, result.printRequestID); CourierClose(conn); /* RETURNS [printRequestID: RequestID] */ if(remove) unlink(FileName); } /* * Wait for the job to complete */ WaitForCompletion(conn, printRequestID) CourierConnection *conn; Printing3_RequestID printRequestID; { static char *statusStrings[] = {"pending", "inProgress", "completed", "completedWithWarning", "unknown", "rejected", "aborted", "canceled", "held"}; #define DONE 0 #define WAIT 1 static char statusActions[] = {WAIT, WAIT, DONE, DONE, DONE, DONE, DONE, DONE, WAIT}; int i, typ, cycle, action; GetPrintRequestStatusResults result; for(cycle = 0;; cycle++) { if (!quiet) printf("try #%d\n", cycle); DURING result = GetPrintRequestStatus(conn, NULL, printRequestID); HANDLER { ExitStatus = X_NORETRY; /* if it got this far... */ switch (Exception.Code) { case ServiceUnavailable: attnmsg("GetReqStat: Service unavailable\n"); break; case SystemError: attnmsg("GetReqStat: System error\n"); break; case Undefined: attnmsg("GetReqStat: Undefined error, number %d\n", CourierErrArgs(UndefinedArgs, problem)); case REJECT_ERROR: attnmsg("GetReqStat: REJECT: type = %d\n", CourierErrArgs(rejectionDetails, designator)); break; default: attnmsg("GetStat: Some random error, code %d\n", Exception.Code); break; } exit(ExitStatus); } END_HANDLER; action = WAIT; /* check out the returned status */ for( i = 0; i < result.status.length; i++ ) { switch (result.status.sequence[i].designator) { case status: typ = (int) result.status.sequence[i].status_case; action = statusActions[typ]; if (!quiet) printf("\tstatus: %s\n", statusStrings[typ]); break; case statusMessage: if(!quiet) printf("\tstatus message (%d bytes): %s\n", strlen(result.status.sequence[i].statusMessage_case), result.status.sequence[i].statusMessage_case); break; default: printf("GetReqStatu: help!\n"); } } if( action == DONE ) return; sleep(3); /* wait three seconds before trying again */ } }