1: /*
2: * $Header: xnsprint.c,v 2.0 85/11/21 07:23:11 jqj 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.0 85/11/21 07:23:11 jqj
12: * 4.3BSD standard release
13: *
14: * Revision 1.1 85/11/20 13:56:53 jqj
15: * Initial revision
16: *
17: * modified 8-6-85 by jqj.
18: * Eliminated any hardwired addresses. Instead, use CH_Enumerate to
19: * find a printer if none is specified. Also, you can now print multiple
20: * files in a single call to xnsprint, and getopt() is used to parse
21: * arguments.
22: */
23: #include <stdio.h>
24: #include <sys/types.h>
25: #include <netns/ns.h>
26: #include <netns/sp.h>
27: #include "Printing3_defs.h"
28: #include <xnscourier/Clearinghouse2.h>
29: #include <xnscourier/except.h>
30: #include <pwd.h>
31: #include <sys/file.h>
32: #include <strings.h>
33:
34: static FILE *ipfile = NULL;
35: static int ExitStatus = 0; /* modified lpd conventions: */
36: /* 0 => Job printed. (successfully sent to print-server) */
37: #define X_GOOD 0
38: /* 1 => Couldn't send job. Retry forever, should go eventually. */
39: #define X_RETRY 1
40: /* 2 => Couldn't send job, Strange error, Retry a limited number*/
41: /* of times. If it still hasn't worked, give up. */
42: #define X_LIMRETRY 2
43: /* 3 => Couldn't send job: Hard error, don't bother retrying, */
44: /* get rid of the job. */
45: #define X_NORETRY 3
46:
47: SendSource(bdtconnection)
48: CourierConnection *bdtconnection;
49: {
50: int count;
51: char buffer[SPPMAXDATA];
52:
53: while ( (count = fread(buffer,1,SPPMAXDATA,ipfile)) > 0 &&
54: BDTwrite(bdtconnection,buffer,count) >= 0 )
55: ;
56: if (count <= 0)
57: BDTclosewrite(bdtconnection); /* last packet with EOM set */
58: else
59: BDTabort(bdtconnection);
60: }
61: /*
62: * misc externals
63: */
64: int remove = 0;
65: int quiet = 0;
66: int attn = 0; /* Write lpr system STATUS file? LCP 850415*/
67: char *attnfile; /* Status file name. LCP 850415 */
68: char *FileName = NULL;
69: char *UserName = NULL;
70: char *Banner = NULL;
71: int copies = 1;
72: Clearinghouse2_Name hostname;
73: char *xnshost = NULL;
74:
75: setxnshost(name)
76: Clearinghouse2_ObjectName name;
77: {
78: extern char *malloc(), *strcpy();
79:
80: if (xnshost == NULL)
81: xnshost = strcpy(malloc(strlen(name.object)+1),name.object);
82: }
83:
84: main(argc, argv)
85: int argc;
86: char **argv;
87: {
88: struct ns_addr *destaddr;
89: CourierConnection *conn;
90: extern struct ns_addr *getXNSaddr();
91: extern struct ns_addr *CH_LookupAddr();
92: Clearinghouse2_Name hostname, defaultname;
93: extern Clearinghouse2_Name CH_StringToName();
94: int opt;
95: extern int optind;
96: extern char *optarg;
97: int errflg = 0;
98:
99: while ((opt = getopt(argc,argv,"c:n:b:P:h:rqa:")) != EOF)
100: switch (opt) {
101: case 'c': /* copies */
102: copies = atoi(optarg);
103: break;
104: case 'n': /* user name */
105: UserName = optarg;
106: break;
107: case 'b': /* file name */
108: Banner = optarg;
109: break;
110: case 'P': /* printer */
111: case 'h': /* host */
112: xnshost = optarg;
113: break;
114: case 'r': /* remove input file when done */
115: remove++;
116: break;
117: case 'q': /* don't print status messages */
118: quiet++;
119: break;
120: case 'a': /* Write lpr STATUS file. Name follows. LCP 850415 */
121: quiet++;
122: attn++;
123: attnfile = optarg;
124: break;
125: default:
126: errflg = 1;
127: }
128: if (errflg) {
129: attnmsg("Usage: %s [-r] [-P host] [-c #] [-n name] [-b banner] file...\n",
130: argv[0]);
131: exit(X_NORETRY);
132: }
133:
134: /* set User Name for banner if necessary */
135: if (UserName == NULL) {
136: struct passwd *pwd, *getpwuid();
137: char *p;
138: extern char *getenv(), *index();
139:
140: UserName = getenv("USER");
141: if ((pwd = getpwuid(getuid())) != NULL) {
142: UserName = pwd->pw_gecos;
143: if (p = index(UserName,','))
144: *p = '\000';
145: }
146: }
147:
148: /* figure out what address we're sending to */
149: CH_NameDefault(&defaultname);/* default from clearinghouse.addresses */
150: if (xnshost == NULL) {
151: /* find the first object in the local domain of the CH
152: * with a printService property. setxnshost sets xnshost
153: * to the name part of the object
154: */
155: hostname = defaultname;
156: hostname.object = "*";
157: CH_Enumerate(hostname,10001,setxnshost);
158: hostname.object = xnshost;
159: }
160: else hostname = CH_StringToName(xnshost,&defaultname);
161: if ((destaddr = CH_LookupAddr(hostname,4)) == NULL) {
162: attnmsg("Invalid address, %s:%s:%s\n",
163: hostname.object,hostname.domain,hostname.organization);
164: exit(X_NORETRY);
165: }
166:
167: /* make sure the printer is available */
168: checkIPstatus(destaddr);
169:
170: for ( ; optind < argc; optind++) {
171: FileName = argv[optind];
172: if (strcmp(FileName,"-") == 0) {
173: ipfile = stdin;
174: FileName = "standard input";
175: }
176: else if ((ipfile = fopen(FileName,"r")) == NULL) {
177: fprintf(stderr, "%s: Can't open %s\n", argv[0], FileName);
178: exit(X_NORETRY);
179: }
180: if(Banner == NULL)
181: Banner = FileName;
182:
183: if (!quiet)
184: printf("Sending to %s...", xnshost);
185: fflush(stdout);
186:
187: sendIPfile(ipfile,destaddr);
188: if (ipfile != stdin)
189: fclose(ipfile);
190: }
191:
192: if (!quiet)
193: printf("Done.\n");
194: exit(X_GOOD);
195: }
196:
197: /*
198: * Check printer status first so we won't dump big interpress
199: * files accross the net unless we're fairly confidant that they'll
200: * be accepted.
201: */
202: checkIPstatus(destaddr)
203: struct ns_addr *destaddr;
204: {
205: CourierConnection *conn;
206: GetPrinterStatusResults StatusResult;
207:
208: do {
209: if (!quiet)
210: printf("Opening connection to %s. ",xnshost);
211: if (attn)
212: attnmsg("Opening connection to %s.\n",xnshost);
213: if ((conn = CourierOpen(destaddr)) == NULL) {
214: attnmsg(stderr,"Can't open connection to %s\n",xnshost);
215: if(remove && !attn)
216: attnmsg(stderr,"Output left in %s\n", FileName);
217: exit(X_LIMRETRY);
218: }
219: if (!quiet)
220: printf("Connected.\n");
221: if (attn)
222: attnmsg("Requesting status.\n");
223: DURING
224: StatusResult = GetPrinterStatus(conn,NULL);
225: HANDLER {
226: ExitStatus = X_LIMRETRY;
227: switch (Exception.Code) {
228: case ServiceUnavailable:
229: attnmsg(stderr,"GetStat: Service unavailable\n");
230: ExitStatus = X_NORETRY;
231: break;
232: case SystemError:
233: attnmsg(stderr,"GetStat: System Error\n");
234: break;
235: case Undefined:
236: attnmsg(stderr,"GetStat: Undefined error, number %d\n",
237: CourierErrArgs(UndefinedArgs,problem));
238: break;
239: case REJECT_ERROR:
240: attnmsg(stderr,"GetStat: REJECT: type = %d\n",
241: CourierErrArgs(rejectionDetails, designator));
242: break;
243: default:
244: attnmsg(stderr,"GetStat: Some random error, code %d\n",
245: Exception.Code);
246: break;
247: }
248: if (remove && !attn)
249: attnmsg(stderr,"Output left in %s\n", FileName);
250: exit(ExitStatus);
251: } END_HANDLER;
252:
253: CourierClose(conn);
254: } while (printresults(StatusResult.status) != 0);
255: }
256:
257: /*
258: * display printer status, return 0 IFF spooler is available
259: */
260: int
261: printresults(status)
262: PrinterStatus status;
263: {
264: int i, typ;
265: static char *spoollist[] = {"available","busy","disabled","full"};
266: static char *formatlist[] = {"available","busy","disabled"};
267: static char *printlist[] = {"available","busy","disabled",
268: "needs attention","needs key operator"};
269: int error = 1;
270: char bufr[256];
271:
272: bufr[0] = '\0';
273: for (i = 0; i < status.length; i++) {
274: switch (status.sequence[i].designator) {
275: case spooler:
276: typ = (int) status.sequence[i].spooler_case;
277: if (!quiet || typ > 1)
278: sprintf(bufr+strlen(bufr),
279: "Spooler: %s; ", spoollist[typ]);
280: error = typ;
281: break;
282: case formatter:
283: typ = (int) status.sequence[i].formatter_case;
284: if (!quiet || typ > 1)
285: sprintf(bufr+strlen(bufr),
286: "Formatter: %s; ", formatlist[typ]);
287: break;
288: case printer:
289: typ = (int) status.sequence[i].printer_case;
290: if (!quiet || typ > 1)
291: sprintf(bufr+strlen(bufr),
292: "Printer: %s. ", printlist[typ]);
293: break;
294: case media:
295: /* printmedia(status.sequence[i].media_case); */
296: break;
297: }
298: }
299: if (bufr[0] != '\0')
300: {
301: if (attn)
302: attnmsg("%s\n",bufr);
303: else
304: printf("%s\n",bufr);
305: }
306:
307: switch(error) {
308: case 0:
309: break;
310: case 1:
311: if (!quiet)
312: printf("Retrying... ");
313: if (bufr[0] != '\0' && attn)
314: attnmsg("Status: Busy. Retrying...\n");
315: fflush(stdout);
316: sleep(15);
317: break;
318: default:
319: if(remove && !attn)
320: attnmsg(stderr, "Output left in %s\n", FileName);
321: exit(1);
322: }
323: return(error);
324: }
325:
326:
327: attnmsg(fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)
328: char *fmt;
329: {
330: char bufr[256];
331: int af;
332:
333: if (attn)
334: {
335: if ((af = open(attnfile,O_TRUNC|O_WRONLY|O_CREAT,0666)) < 0)
336: return; /* Oh Well. */
337:
338: sprintf(bufr,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);
339:
340: (void) write(af,bufr,strlen(bufr)); /* In case of error??? */
341: close(af);
342: }
343: else
344: fprintf(stderr,fmt,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);
345: }
346:
347: sendIPfile(ipfile,destaddr)
348: FILE *ipfile;
349: struct ns_addr *destaddr;
350: {
351: PrintResults result;
352: CourierConnection *conn;
353: PrintAttributes attributes;
354: PrintOptions options;
355: char *malloc();
356:
357: /* only use sender name and file name, no date */
358: attributes.length = 2;
359: attributes.sequence = malloc( 2 * sizeof(*attributes.sequence));
360: attributes.sequence[0].designator = printObjectName;
361: attributes.sequence[0].printObjectName_case = Banner;
362: attributes.sequence[1].designator = senderName;
363: attributes.sequence[1].senderName_case = UserName;
364:
365: options.length = 1;
366: options.sequence = malloc( sizeof(*options.sequence));
367: options.sequence[0].designator = copyCount;
368: options.sequence[0].copyCount_case = copies;
369:
370: again:
371: if (!quiet)
372: printf("Opening connection to %s. ",xnshost);
373: if (attn)
374: attnmsg("Opening connection to %s.\n",xnshost);
375:
376: if ((conn = CourierOpen(destaddr)) == NULL) {
377: attnmsg(stderr,"Can't open connection to %s\n",xnshost);
378: if(remove && !attn)
379: attnmsg(stderr,"Output left in %s\n", FileName);
380: exit(X_LIMRETRY);
381: }
382:
383: if (!quiet)
384: printf("Connected.\n");
385: if (attn)
386: attnmsg("Sending to %s\n",xnshost);
387:
388: DURING
389: result = Print(conn, SendSource, BulkData1_immediateSource,
390: attributes, options);
391: HANDLER {
392: ExitStatus = X_RETRY;
393: switch (Exception.Code) {
394: case Busy:
395: if (!quiet)
396: printf("Busy, retrying...\n");
397: if (attn)
398: attnmsg("Busy, retrying...\n");
399: CourierClose(conn);
400: sleep(15);
401: if (rewind(ipfile) < 0) {
402: ExitStatus = X_LIMRETRY;
403: attnmsg(stderr,"Can't rewind file\n");
404: }
405: goto again;
406: case ConnectionError:
407: ExitStatus = X_LIMRETRY;
408: attnmsg(stderr,"Connection error, %d\n",
409: CourierErrArgs(ConnectionErrorArgs,problem));
410: break;
411: case InsufficientSpoolSpace:
412: attnmsg(stderr,"Insufficient Spool Space error\n");
413: break;
414: case InvalidPrintParameters:
415: ExitStatus = X_LIMRETRY;
416: attnmsg(stderr,"InvalidPrintParameters error\n");
417: break;
418: case MasterTooLarge:
419: ExitStatus=X_NORETRY;
420: attnmsg(stderr,"MasterTooLarge error\n");
421: break;
422: case MediumUnavailable:
423: ExitStatus=X_NORETRY;
424: attnmsg(stderr,"MediumUnavailable error\n");
425: break;
426: case ServiceUnavailable:
427: ExitStatus=X_NORETRY;
428: attnmsg(stderr,"ServiceUnavailable error\n");
429: break;
430: case SpoolingDisabled:
431: attnmsg(stderr,"SpoolingDisabled\n");
432: break;
433: case SpoolingQueueFull:
434: attnmsg(stderr,"SpoolingQueueFull error\n");
435: break;
436: case SystemError:
437: ExitStatus = X_LIMRETRY;
438: attnmsg(stderr,"System Error\n");
439: break;
440: case TooManyClients:
441: attnmsg(stderr,"TooManyClients error\n");
442: break;
443: case TransferError:
444: ExitStatus = X_LIMRETRY;
445: attnmsg(stderr,"TransferError error\n");
446: break;
447: case Undefined:
448: attnmsg(stderr,"Undefined error, number %d\n",
449: CourierErrArgs(UndefinedArgs,problem));
450: break;
451: case REJECT_ERROR:
452: ExitStatus = X_LIMRETRY;
453: attnmsg(stderr,"REJECT: type = %d\n",
454: CourierErrArgs(rejectionDetails, designator));
455: break;
456: default:
457: ExitStatus = X_LIMRETRY;
458: attnmsg(stderr,"Some random error, code %d\n",
459: Exception.Code);
460: break;
461: }
462: if(remove && !attn)
463: attnmsg(stderr,"Output left in %s\n", FileName);
464: exit(ExitStatus);
465: } END_HANDLER;
466:
467: CourierClose(conn);
468:
469: /* RETURNS [printRequestID: RequestID] */
470: if(remove) unlink(FileName);
471: }