|
|
1.1 root 1: /*
2: * $Header: xnsprint.c,v 2.4 87/01/09 16:34:23 ed Exp $
3: *
4: * a program to print InterPress masters on an InterPress printer via
5: * Ethernet. Uses xns Courier.
6: * This version runs on 4.3BSD only!
7: */
8:
9: /*
10: * $Log: xnsprint.c,v $
11: * Revision 2.4 87/01/09 16:34:23 ed
12: * Webster version
13: *
14: * Revision 2.4 87/01/09 16:34:23 ed
15: * Added -W flag to wait until printing is completed (from Lee Moore)
16: *
17: * Revision 2.3 86/12/11 04:43:34 jqj
18: * Added support for -s and -m flags.
19: *
20: * Revision 2.2 86/09/07 06:57:41 jqj
21: * Fixed inconsistent calls to attnmsg() by eliminating stderr first arg.
22: * Changed banner not to use "Cornell Computer Science".
23: *
24: * Revision 2.1 86/05/16 11:04:18 jqj
25: * fix to correspond to new enumeration semantics (tags are now global)
26: *
27: * Revision 2.0 85/11/21 07:23:11 jqj
28: * 4.3BSD standard release
29: *
30: * Revision 1.1 85/11/20 13:56:53 jqj
31: * Initial revision
32: *
33: * modified 8-6-85 by jqj.
34: * Eliminated any hardwired addresses. Instead, use CH_Enumerate to
35: * find a printer if none is specified. Also, you can now print multiple
36: * files in a single call to xnsprint, and getopt() is used to parse
37: * arguments.
38: */
39: #include <stdio.h>
40: #include <sys/types.h>
41: #include <netns/ns.h>
42: #include <netns/sp.h>
43: #include "Printing3_defs.h"
44: #include <xnscourier/Clearinghouse2.h>
45: #include <xnscourier/except.h>
46: #include <pwd.h>
47: #include <sys/file.h>
48: #include <strings.h>
49:
50: static FILE *ipfile = NULL;
51: static int ExitStatus = 0; /* modified lpd conventions: */
52: /* 0 => Job printed. (successfully sent to print-server) */
53: #define X_GOOD 0
54: /* 1 => Couldn't send job. Retry forever, should go eventually. */
55: #define X_RETRY 1
56: /* 2 => Couldn't send job, Strange error, Retry a limited number*/
57: /* of times. If it still hasn't worked, give up. */
58: #define X_LIMRETRY 2
59: /* 3 => Couldn't send job: Hard error, don't bother retrying, */
60: /* get rid of the job. */
61: #define X_NORETRY 3
62:
63: static struct {
64: char * sizename;
65: int sizevalue;
66: } papersizetable[] = {
67: "usLetter", (int) usLetter, /* 1 */
68: "usLegal", (int) usLegal, /* 2 */
69: "a0", (int) a0, /* 3 */
70: "a1", (int) a1, /* 4 */
71: "a2", (int) a2, /* 5 */
72: "a3", (int) a3, /* 6 */
73: "a4", (int) a4, /* 7 */
74: "a5", (int) a5, /* 8 */
75: "a6", (int) a6, /* 9 */
76: "a7", (int) a7, /* 10 */
77: "a8", (int) a8, /* 11 */
78: "a9", (int) a9, /* 12 */
79: "a10", (int) a10, /* 35 */
80: "isoB0", (int) isoB0, /* 13 */
81: "isoB1", (int) isoB1, /* 14 */
82: "isoB2", (int) isoB2, /* 15 */
83: "isoB3", (int) isoB3, /* 16 */
84: "isoB4", (int) isoB4, /* 17 */
85: "isoB5", (int) isoB5, /* 18 */
86: "isoB6", (int) isoB6, /* 19 */
87: "isoB7", (int) isoB7, /* 20 */
88: "isoB8", (int) isoB8, /* 21 */
89: "isoB9", (int) isoB9, /* 22 */
90: "isoB10", (int) isoB10, /* 23 */
91: "jisB0", (int) jisB0, /* 24 */
92: "jisB1", (int) jisB1, /* 25 */
93: "jisB2", (int) jisB2, /* 26 */
94: "jisB3", (int) jisB3, /* 27 */
95: "jisB4", (int) jisB4, /* 28 */
96: "jisB5", (int) jisB5, /* 29 */
97: "jisB6", (int) jisB6, /* 30 */
98: "jisB7", (int) jisB7, /* 31 */
99: "jisB8", (int) jisB8, /* 32 */
100: "jisB9", (int) jisB9, /* 33 */
101: "jisB10", (int) jisB10, /* 34 */
102: (char *) 0, 0
103: };
104:
105: SendSource(bdtconnection)
106: CourierConnection *bdtconnection;
107: {
108: int count;
109: char buffer[SPPMAXDATA];
110:
111: while ( (count = fread(buffer,1,SPPMAXDATA,ipfile)) > 0 &&
112: BDTwrite(bdtconnection,buffer,count) >= 0 )
113: ;
114: if (count <= 0)
115: BDTclosewrite(bdtconnection); /* last packet with EOM set */
116: else
117: BDTabort(bdtconnection);
118: }
119: /*
120: * misc externals
121: */
122: int remove = 0;
123: int quiet = 0;
124: int attn = 0; /* Write lpr system STATUS file? LCP 850415*/
125: char *attnfile; /* Status file name. LCP 850415 */
126: char *FileName = NULL;
127: char *UserName = NULL;
128: char *Banner = NULL;
129: int copies = 1;
130: Medium paperchoice;
131: char *UserMessage = NULL;
132: Clearinghouse2_Name hostname;
133: char *xnshost = NULL;
134: int WaitFlag = 0; /* wait until job is printed ? LCM */
135:
136: setxnshost(name)
137: Clearinghouse2_ObjectName name;
138: {
139: extern char *malloc(), *strcpy();
140:
141: if (xnshost == NULL)
142: xnshost = strcpy(malloc(strlen(name.object)+1),name.object);
143: }
144:
145: main(argc, argv)
146: int argc;
147: char **argv;
148: {
149: struct ns_addr *destaddr;
150: CourierConnection *conn;
151: extern struct ns_addr *getXNSaddr();
152: extern struct ns_addr *CH_LookupAddr();
153: Clearinghouse2_Name defaultname;
154: extern Clearinghouse2_Name CH_StringToName();
155: int opt;
156: extern int optind;
157: extern char *optarg;
158: int errflg = 0;
159: int i;
160:
161: paperchoice.designator = paper;
162: paperchoice.paper_case.designator = knownSize;
163: paperchoice.paper_case.knownSize_case = usLetter;
164:
165: while ((opt = getopt(argc,argv,"c:n:b:P:h:rqa:lm:s:W")) != EOF)
166: switch (opt) {
167: case 'c': /* copies */
168: copies = atoi(optarg);
169: break;
170: case 'n': /* user name */
171: UserName = optarg;
172: break;
173: case 'b': /* file name */
174: Banner = optarg;
175: break;
176: case 'P': /* printer */
177: case 'h': /* host */
178: xnshost = optarg;
179: break;
180: case 'r': /* remove input file when done */
181: remove++;
182: break;
183: case 'q': /* don't print status messages */
184: quiet++;
185: break;
186: case 'a': /* Write lpr STATUS file. Name follows. LCP 850415 */
187: quiet++;
188: attn++;
189: attnfile = optarg;
190: break;
191: case 'l': /* use legal-sized (long) paper */
192: paperchoice.paper_case.knownSize_case = usLegal;
193: break;
194: case 'm': /* message field follows (default to XNS name) */
195: UserMessage = optarg;
196: break;
197: case 's': /* papersize name follows */
198: for (i = 0; papersizetable[i].sizename != NULL; i++)
199: if (strcmp(optarg,papersizetable[i].sizename) == 0) {
200: *(int*)& paperchoice.paper_case.knownSize_case =
201: papersizetable[i].sizevalue;
202: goto gotsize;
203: }
204: *(int*)& paperchoice.paper_case.knownSize_case = atoi(optarg);
205: gotsize:
206: break;
207: case 'W': /* wait for the job to be printed LCM */
208: WaitFlag++;
209: break;
210: default:
211: errflg = 1;
212: }
213: if (errflg) {
214: attnmsg("Usage: %s [-r] [-P host] [-c #] [-n name] [-b banner] [-l] [-s size] [-m message] [-W] file...\n",
215: argv[0]);
216: exit(X_NORETRY);
217: }
218:
219: /* set User Name for banner if necessary */
220: if (UserName == NULL) {
221: struct passwd *pwd, *getpwuid();
222: char *p;
223: extern char *getenv(), *index();
224:
225: UserName = getenv("USER");
226: if ((pwd = getpwuid(getuid())) != NULL) {
227: UserName = pwd->pw_gecos;
228: if (p = index(UserName,','))
229: *p = '\000';
230: }
231: }
232:
233: /* figure out what address we're sending to */
234: CH_NameDefault(&defaultname);/* default from clearinghouse.addresses */
235: if (xnshost == NULL) {
236: xnshost= getenv("PRINTER");
237: if ( (xnshost == NULL) || (*xnshost == '\0') ) {
238: /* find the first object in the local domain of the CH
239: * with a printService property. setxnshost sets xnshost
240: * to the name part of the object
241: */
242: hostname = defaultname;
243: hostname.object = "*";
244: CH_Enumerate(hostname,10001,setxnshost);
245: hostname.object = xnshost;
246: } else
247: hostname = CH_StringToName(xnshost,&defaultname);
248: }
249: else hostname = CH_StringToName(xnshost,&defaultname);
250:
251: if ((destaddr = CH_LookupAddr(hostname,4)) == NULL) {
252: attnmsg("Invalid address, %s:%s:%s\n",
253: hostname.object,hostname.domain,hostname.organization);
254: exit(X_NORETRY);
255: }
256:
257: /* make sure the printer is available */
258: checkIPstatus(destaddr);
259:
260: for ( ; optind < argc; optind++) {
261: FileName = argv[optind];
262: if (strcmp(FileName,"-") == 0) {
263: ipfile = stdin;
264: FileName = "standard input";
265: }
266: else if ((ipfile = fopen(FileName,"r")) == NULL) {
267: fprintf(stderr, "%s: Can't open %s\n", argv[0], FileName);
268: exit(X_NORETRY);
269: }
270: if(Banner == NULL)
271: Banner = FileName;
272:
273: if (!quiet)
274: printf("Sending to %s...", xnshost);
275: fflush(stdout);
276:
277: sendIPfile(ipfile,destaddr);
278: if (ipfile != stdin)
279: fclose(ipfile);
280: }
281:
282: if (!quiet)
283: printf("Done.\n");
284: exit(X_GOOD);
285: }
286:
287: /*
288: * Check printer status first so we won't dump big interpress
289: * files accross the net unless we're fairly confidant that they'll
290: * be accepted.
291: */
292: checkIPstatus(destaddr)
293: struct ns_addr *destaddr;
294: {
295: CourierConnection *conn;
296: GetPrinterStatusResults StatusResult;
297:
298: do {
299: if (!quiet)
300: printf("Opening connection to %s. ",xnshost);
301: if (attn)
302: attnmsg("Opening connection to %s.\n",xnshost);
303: if ((conn = CourierOpen(destaddr)) == NULL) {
304: attnmsg("Can't open connection to %s\n",xnshost);
305: if(remove && !attn)
306: attnmsg("Output left in %s\n", FileName);
307: exit(X_LIMRETRY);
308: }
309: if (!quiet)
310: printf("Connected.\n");
311: if (attn)
312: attnmsg("Requesting status.\n");
313: DURING
314: StatusResult = GetPrinterStatus(conn,NULL);
315: HANDLER {
316: ExitStatus = X_LIMRETRY;
317: switch (Exception.Code) {
318: case ServiceUnavailable:
319: attnmsg("GetStat: Service unavailable\n");
320: ExitStatus = X_NORETRY;
321: break;
322: case SystemError:
323: attnmsg("GetStat: System Error\n");
324: break;
325: case Undefined:
326: attnmsg("GetStat: Undefined error, number %d\n",
327: CourierErrArgs(UndefinedArgs,problem));
328: break;
329: case REJECT_ERROR:
330: attnmsg("GetStat: REJECT: type = %d\n",
331: CourierErrArgs(rejectionDetails, designator));
332: break;
333: default:
334: attnmsg("GetStat: Some random error, code %d\n",
335: Exception.Code);
336: break;
337: }
338: if (remove && !attn)
339: attnmsg("Output left in %s\n", FileName);
340: exit(ExitStatus);
341: } END_HANDLER;
342:
343: CourierClose(conn);
344: } while (printresults(StatusResult.status) != 0);
345: }
346:
347: /*
348: * display printer status, return 0 IFF spooler is available
349: */
350: int
351: printresults(status)
352: PrinterStatus status;
353: {
354: int i, typ;
355: static char *spoollist[] = {"available","busy","disabled","full"};
356: static char *formatlist[] = {"available","busy","disabled"};
357: static char *printlist[] = {"available","busy","disabled",
358: "needs attention","needs key operator"};
359: int error = 1;
360: char bufr[256];
361:
362: bufr[0] = '\0';
363: for (i = 0; i < status.length; i++) {
364: switch (status.sequence[i].designator) {
365: case spooler:
366: typ = (int) status.sequence[i].spooler_case;
367: if (!quiet || typ > 1)
368: sprintf(bufr+strlen(bufr),
369: "Spooler: %s; ", spoollist[typ]);
370: error = typ;
371: break;
372: case formatter:
373: typ = (int) status.sequence[i].formatter_case;
374: if (!quiet || typ > 1)
375: sprintf(bufr+strlen(bufr),
376: "Formatter: %s; ", formatlist[typ]);
377: break;
378: case printer:
379: typ = (int) status.sequence[i].printer_case;
380: if (!quiet || typ > 1)
381: sprintf(bufr+strlen(bufr),
382: "Printer: %s. ", printlist[typ]);
383: break;
384: case media:
385: /* printmedia(status.sequence[i].media_case); */
386: break;
387: }
388: }
389: if (bufr[0] != '\0')
390: {
391: if (attn)
392: attnmsg("%s\n",bufr);
393: else
394: printf("%s\n",bufr);
395: }
396:
397: switch(error) {
398: case 0:
399: break;
400: case 1:
401: if (!quiet)
402: printf("Retrying... ");
403: if (bufr[0] != '\0' && attn)
404: attnmsg("Status: Busy. Retrying...\n");
405: fflush(stdout);
406: sleep(15);
407: break;
408: default:
409: if(remove && !attn)
410: attnmsg( "Output left in %s\n", FileName);
411: exit(1);
412: }
413: return(error);
414: }
415:
416:
417: attnmsg(fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)
418: char *fmt;
419: {
420: char bufr[256];
421: int af;
422:
423: if (attn)
424: {
425: if ((af = open(attnfile,O_TRUNC|O_WRONLY|O_CREAT,0666)) < 0)
426: return; /* Oh Well. */
427:
428: sprintf(bufr,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);
429:
430: (void) write(af,bufr,strlen(bufr)); /* In case of error??? */
431: close(af);
432: }
433: else
434: fprintf(stderr,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);
435: }
436:
437: sendIPfile(ipfile,destaddr)
438: FILE *ipfile;
439: struct ns_addr *destaddr;
440: {
441: PrintResults result;
442: CourierConnection *conn;
443: PrintAttributes attributes;
444: PrintOptions options;
445: char *malloc();
446:
447: /* only use sender name and file name, no date */
448: attributes.length = 2;
449: attributes.sequence = malloc(attributes.length *
450: sizeof(*attributes.sequence));
451: attributes.sequence[0].designator = printObjectName;
452: attributes.sequence[0].printObjectName_case = Banner;
453: attributes.sequence[1].designator = senderName;
454: attributes.sequence[1].senderName_case = UserName;
455:
456: options.length = 3;
457: options.sequence = malloc(options.length *
458: sizeof(*options.sequence));
459: options.sequence[0].designator = copyCount;
460: options.sequence[0].copyCount_case = copies;
461: options.sequence[1].designator = mediumHint;
462: options.sequence[1].mediumHint_case = paperchoice;
463: options.sequence[2].designator = message;
464: options.sequence[2].message_case =
465: UserMessage ? UserMessage :
466: sprintf(malloc(44),"%s:%s:%s",
467: hostname.object,hostname.domain,
468: hostname.organization)
469: ;
470:
471: again:
472: if (!quiet)
473: printf("Opening connection to %s. ",xnshost);
474: if (attn)
475: attnmsg("Opening connection to %s.\n",xnshost);
476:
477: if ((conn = CourierOpen(destaddr)) == NULL) {
478: attnmsg("Can't open connection to %s\n",xnshost);
479: if(remove && !attn)
480: attnmsg("Output left in %s\n", FileName);
481: exit(X_LIMRETRY);
482: }
483:
484: if (!quiet)
485: printf("Connected.\n");
486: if (attn)
487: attnmsg("Sending to %s\n",xnshost);
488:
489: DURING
490: result = Print(conn, SendSource, BulkData1_immediateSource,
491: attributes, options);
492: HANDLER {
493: ExitStatus = X_RETRY;
494: switch (Exception.Code) {
495: case Busy:
496: if (!quiet)
497: printf("Busy, retrying...\n");
498: if (attn)
499: attnmsg("Busy, retrying...\n");
500: CourierClose(conn);
501: sleep(15);
502: if (rewind(ipfile) < 0) {
503: ExitStatus = X_LIMRETRY;
504: attnmsg("Can't rewind file\n");
505: }
506: goto again;
507: case ConnectionError:
508: ExitStatus = X_LIMRETRY;
509: attnmsg("Connection error, %d\n",
510: CourierErrArgs(ConnectionErrorArgs,problem));
511: break;
512: case InsufficientSpoolSpace:
513: attnmsg("Insufficient Spool Space error\n");
514: break;
515: case InvalidPrintParameters:
516: ExitStatus = X_LIMRETRY;
517: attnmsg("InvalidPrintParameters error\n");
518: break;
519: case MasterTooLarge:
520: ExitStatus=X_NORETRY;
521: attnmsg("MasterTooLarge error\n");
522: break;
523: case MediumUnavailable:
524: ExitStatus=X_NORETRY;
525: attnmsg("MediumUnavailable error\n");
526: break;
527: case ServiceUnavailable:
528: ExitStatus=X_NORETRY;
529: attnmsg("ServiceUnavailable error\n");
530: break;
531: case SpoolingDisabled:
532: attnmsg("SpoolingDisabled\n");
533: break;
534: case SpoolingQueueFull:
535: attnmsg("SpoolingQueueFull error\n");
536: break;
537: case SystemError:
538: ExitStatus = X_LIMRETRY;
539: attnmsg("System Error\n");
540: break;
541: case TooManyClients:
542: attnmsg("TooManyClients error\n");
543: break;
544: case TransferError:
545: ExitStatus = X_LIMRETRY;
546: attnmsg("TransferError error\n");
547: break;
548: case Undefined:
549: attnmsg("Undefined error, number %d\n",
550: CourierErrArgs(UndefinedArgs,problem));
551: break;
552: case REJECT_ERROR:
553: ExitStatus = X_LIMRETRY;
554: attnmsg("REJECT: type = %d\n",
555: CourierErrArgs(rejectionDetails, designator));
556: break;
557: default:
558: ExitStatus = X_LIMRETRY;
559: attnmsg("Some random error, code %d\n",
560: Exception.Code);
561: break;
562: }
563: if(remove && !attn)
564: attnmsg("Output left in %s\n", FileName);
565: exit(ExitStatus);
566: } END_HANDLER;
567:
568: if (WaitFlag) /* wait for completion LCM */
569: WaitForCompletion(conn, result.printRequestID);
570: CourierClose(conn);
571:
572: /* RETURNS [printRequestID: RequestID] */
573: if(remove) unlink(FileName);
574: }
575:
576: /*
577: * Wait for the job to complete
578: */
579: WaitForCompletion(conn, printRequestID)
580: CourierConnection *conn;
581: Printing3_RequestID printRequestID;
582: {
583: static char *statusStrings[] = {"pending", "inProgress", "completed",
584: "completedWithWarning", "unknown", "rejected", "aborted",
585: "canceled", "held"};
586: #define DONE 0
587: #define WAIT 1
588: static char statusActions[] = {WAIT, WAIT, DONE,
589: DONE, DONE, DONE, DONE,
590: DONE, WAIT};
591: int i, typ,
592: cycle,
593: action;
594: GetPrintRequestStatusResults result;
595:
596: for(cycle = 0;; cycle++) {
597: if (!quiet)
598: printf("try #%d\n", cycle);
599:
600: DURING
601: result = GetPrintRequestStatus(conn, NULL, printRequestID);
602: HANDLER {
603: ExitStatus = X_NORETRY; /* if it got this far... */
604:
605: switch (Exception.Code) {
606: case ServiceUnavailable:
607: attnmsg("GetReqStat: Service unavailable\n");
608: break;
609: case SystemError:
610: attnmsg("GetReqStat: System error\n");
611: break;
612: case Undefined:
613: attnmsg("GetReqStat: Undefined error, number %d\n",
614: CourierErrArgs(UndefinedArgs, problem));
615:
616: case REJECT_ERROR:
617: attnmsg("GetReqStat: REJECT: type = %d\n",
618: CourierErrArgs(rejectionDetails, designator));
619: break;
620: default:
621: attnmsg("GetStat: Some random error, code %d\n",
622: Exception.Code);
623: break;
624: }
625:
626: exit(ExitStatus);
627: } END_HANDLER;
628:
629: action = WAIT;
630:
631: /* check out the returned status */
632: for( i = 0; i < result.status.length; i++ ) {
633: switch (result.status.sequence[i].designator) {
634: case status:
635: typ = (int) result.status.sequence[i].status_case;
636: action = statusActions[typ];
637:
638: if (!quiet)
639: printf("\tstatus: %s\n", statusStrings[typ]);
640:
641: break;
642:
643: case statusMessage:
644: if(!quiet)
645: printf("\tstatus message (%d bytes): %s\n",
646: strlen(result.status.sequence[i].statusMessage_case),
647: result.status.sequence[i].statusMessage_case);
648: break;
649:
650: default:
651: printf("GetReqStatu: help!\n");
652: }
653: }
654:
655: if( action == DONE )
656: return;
657:
658: sleep(3); /* wait three seconds before trying again */
659: }
660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.