#include #include #include #include #include #include #include #include #include #define REDIALTIMEOUT 15 #ifdef PLAN9 #include #endif #define TIMEOUT 600 char tmpfilename[L_tmpnam+1]; int alarmstate = 0; int debugflag = 1; int killflag = 0; int statflag = 0; #define NAMELEN 28 static int call(char *clone, char *dest, int *cfdp, char *dir, char *local) { int fd, cfd; int n; char name[3*NAMELEN+5]; char data[3*NAMELEN+10]; char *p; cfd = open(clone, O_RDWR); if(cfd < 0) return -1; /* get directory name */ n = read(cfd, name, sizeof(name)-1); if(n < 0){ close(cfd); return -1; } name[n] = 0; p = strrchr(clone, '/'); *p = 0; if(dir) sprintf(dir, "%.*s/%.*s", 2*NAMELEN+1, clone, NAMELEN, name); sprintf(data, "%.*s/%.*s/data", 2*NAMELEN+1, clone, NAMELEN, name); /* set local side (port number, for example) if we need to */ if(local) sprintf(name, "connect %.*s %.*s", 2*NAMELEN, dest, NAMELEN, local); else sprintf(name, "connect %.*s", 2*NAMELEN, dest); /* connect */ if(write(cfd, name, strlen(name)) < 0){ close(cfd); return -1; } /* open data connection */ fd = open(data, O_RDWR); if(fd < 0){ close(cfd); return -1; } if(cfdp) *cfdp = cfd; else close(cfd); return fd; } int dialalt(char *dest, char *local, char *dir, int *cfdp) { char net[128]; char clone[NAMELEN+12]; char *p; int n; int fd; int rv; /* go for a standard form net!... */ p = strchr(dest, '!'); if(p == 0){ sprintf(net, "/net.alt/tcp!%.*s", sizeof(net)-5, dest); } else { strncpy(net, dest, sizeof(net)-1); net[sizeof(net)-1] = 0; } /* call the connection server */ fd = open("/net.alt/cs", O_RDWR); if(fd < 0){ /* no connection server, don't translate */ p = strchr(net, '!'); *p++ = 0; sprintf(clone, "/net.alt/%s/clone", net); return call(clone, p, cfdp, dir, local); } /* * send dest to connection to translate */ if(write(fd, net, strlen(net)) < 0){ close(fd); return -1; } /* * loop through each address from the connection server till * we get one that works. */ rv = -1; lseek(fd, 0, 0); while((n = read(fd, net, sizeof(net) - 1)) > 0){ net[n] = 0; p = strchr(net, ' '); if(p == 0) continue; *p++ = 0; rv = call(net, p, cfdp, dir, local); if(rv >= 0) break; } close(fd); return rv; } void cleanup(void) { unlink(tmpfilename); } #define SBSIZE 8192 unsigned char sendbuf[SBSIZE]; void debug(char *str) { if (debugflag) fprintf(stderr, "%s", str); } void alarmhandler(int sig) { fprintf(stderr, "timeout occurred, check printer.\n"); exit(2); } /* send a message after each WARNPC percent of data sent */ #define WARNPC 5 int copyfile(int in, int out, int tosend) { int n; int sent = 0; int percent = 0; while ((n=read(in, sendbuf, SBSIZE)) > 0) { alarm(TIMEOUT); alarmstate = 1; if (write(out, sendbuf, n) != n) { alarm(0); fprintf(stderr, "write failed\n"); return(0); } alarm(0); sent += n; if (tosend && ((sent*100/tosend)>=(percent+WARNPC))) { percent += WARNPC; fprintf(stderr, ": %5.2f%% sent\n", sent*100.0/tosend); } } return(!n); } char strbuf[120]; char hostname[MAXHOSTNAMELEN], *username, *printername, *killarg; char *inputname; char filetype = 'o'; /* 'o' is for PostScript */ int seqno = 1; void killjob(int printerfd) { int strlength; if (printername==0) { fprintf(stderr, "no printer name\n"); exit(1); } if (username==0) { fprintf(stderr, "no user name given\n"); exit(1); } if (killarg==0) { fprintf(stderr, "no job to kill\n"); exit(1); } sprintf(strbuf, "%c%s %s %s\n", '\5', printername, username, killarg); strlength = strlen(strbuf); if (write(printerfd, strbuf, strlength) != strlength) { fprintf(stderr, "write(printer) error\n"); exit(1); } copyfile(printerfd, 2, 0); } void checkqueue(int printerfd) { int n, strlength; unsigned char sendbuf[1]; sprintf(strbuf, "%c%s\n", '\4', printername); strlength = strlen(strbuf); if (write(printerfd, strbuf, strlength) != strlength) { fprintf(stderr, "write(printer) error\n"); exit(1); } copyfile(printerfd, 2, 0); /* while ((n=read(printerfd, sendbuf, 1)) > 0) { write(2, sendbuf, n); } */ } void getack(int printerfd, int as) { char resp; int rv; alarm(TIMEOUT); alarmstate = as; if ((rv=read(printerfd, &resp, 1)) != 1 || resp != '\0') { fprintf(stderr, "getack failed: read returned %d, read value (if any) %d, alarmstate=%d\n", rv, resp, alarmstate); exit(1); } alarm(0); } /* send control file */ void sendctrl(int printerfd) { char cntrlstrbuf[256]; int strlength, cntrlen; sprintf(cntrlstrbuf, "H%s\nP%s\n%cdfA%3.3d%s\n", hostname, username, filetype, seqno, hostname); cntrlen = strlen(cntrlstrbuf); sprintf(strbuf, "%c%d cfA%3.3d%s\n", '\2', cntrlen, seqno, hostname); strlength = strlen(strbuf); if (write(printerfd, strbuf, strlength) != strlength) { fprintf(stderr, "write(printer) error\n"); exit(1); } getack(printerfd, 3); if (write(printerfd, cntrlstrbuf, cntrlen) != cntrlen) { fprintf(stderr, "write(printer) error\n"); exit(1); } if (write(printerfd, "\0", 1) != 1) { fprintf(stderr, "write(printer) error\n"); exit(1); } getack(printerfd, 4); } /* send data file */ void senddata(int inputfd, int printerfd, int size) { int strlength; sprintf(strbuf, "%c%d dfA%3.3d%s\n", '\3', size, seqno, hostname); strlength = strlen(strbuf); if (write(printerfd, strbuf, strlength) != strlength) { fprintf(stderr, "write(printer) error\n"); exit(1); } getack(printerfd, 5); if (!copyfile(inputfd, printerfd, size)) { fprintf(stderr, "failed to send file to printer\n"); exit(1); } if (write(printerfd, "\0", 1) != 1) { fprintf(stderr, "write(printer) error\n"); exit(1); } fprintf(stderr, "%d bytes sent, status: waiting for end of job\n", size); getack(printerfd, 6); } void sendjob(int inputfd, int printerfd) { struct stat statbuf; int strlength; if (fstat(inputfd, &statbuf) < 0) { fprintf(stderr, "fstat(%s) failed\n", inputname); exit(1); } sprintf(strbuf, "%c%s\n", '\2', printername); strlength = strlen(strbuf); if (write(printerfd, strbuf, strlength) != strlength) { fprintf(stderr, "write(printer) error\n"); exit(1); } getack(printerfd, 2); debug("send data\n"); senddata(inputfd, printerfd, statbuf.st_size); debug("send control info\n"); sendctrl(printerfd); fprintf(stderr, "%d bytes sent, status: end of job\n", statbuf.st_size); } main(int argc, char *argv[]) { int c, usgflg = 0; char *desthostname; char *hnend; int printerfd; int inputfd; int sendport; char portstr[4]; if (signal(SIGALRM, alarmhandler) == SIG_ERR) { fprintf(stderr, "failed to set alarm handler\n"); exit(1); } while ((c = getopt(argc, argv, "Dd:k:qt:H:P:")) != -1) switch (c) { case 'D': debugflag = 1; debug("debugging on\n"); break; case 'd': printername = optarg; break; case 'k': if (statflag) { fprintf(stderr, "cannot have both -k and -q flags\n"); exit(1); } killflag = 1; killarg = optarg; break; case 'q': if (killflag) { fprintf(stderr, "cannot have both -q and -k flags\n"); exit(1); } statflag = 1; break; case 't': switch (filetype) { case 'c': case 'd': case 'f': case 'g': case 'l': case 'n': case 'o': case 'p': case 'r': case 't': case 'v': case 'z': filetype = optarg[0]; break; default: usgflg++; break; } break; case 'H': strncpy(hostname, optarg, MAXHOSTNAMELEN); break; case 'P': username = optarg; break; default: case '?': fprintf(stderr, "unknown option %c\n", c); usgflg++; } if (argc < 2) usgflg++; if (optind < argc) { desthostname = argv[optind++]; } else usgflg++; if (usgflg) { fprintf(stderr, "usage: to send a job - %s -d printer -H hostname -P username [-t[cdfgklnoprtvz]] desthost [filename]\n", argv[0]); fprintf(stderr, " to check status - %s -d printer -q desthost\n", argv[0]); fprintf(stderr, " to kill a job - %s -d printer -P username -k jobname desthost\n", argv[0]); exit(1); } /* make sure the file to send is here and ready * otherwise the TCP connection times out. */ if (!statflag && !killflag) { if (optind < argc) { inputname = argv[optind++]; debug("open("); debug(inputname); debug(")\n"); inputfd = open(inputname, O_RDONLY); if (inputfd < 0) { fprintf(stderr, "open(%s) failed\n", inputname); exit(1); } } else { inputname = "stdin"; tmpnam(tmpfilename); debug("using stdin\n"); if ((inputfd = open(tmpfilename, O_RDWR|O_CREAT, 0600)) < 0) { fprintf(stderr, "open(%s) failed\n", tmpfilename); exit(1); } atexit(cleanup); debug("copy input to temp file\n"); if (!copyfile(0, inputfd, 0)) { fprintf(stderr, "failed to copy file to temporary file\n"); exit(1); } if (lseek(inputfd, 0, 0) < 0) { fprintf(stderr, "failed to seek back to the beginning of the temporary file\n"); exit(1); } } } fprintf(stderr, "connecting to port 515 on remote host\n"); sprintf(strbuf, "tcp!%s!515", desthostname); for (sendport=721; sendport<=731; sendport++) { sprintf(portstr, "%3.3d", sendport); fprintf(stderr, " trying from port %s...", portstr); debug(" dial("); debug(strbuf); debug(", "); debug(portstr); debug(", 0, 0) ..."); printerfd = dialalt(strbuf, portstr, 0, 0); if (printerfd >= 0) { fprintf(stderr, "connected\n"); break; } fprintf(stderr, "failed\n"); sleep(REDIALTIMEOUT); } if (printerfd < 0) { fprintf(stderr, "Cannot open a valid port!\n"); fprintf(stderr, "- All source ports [721-731] may be busy.\n"); fprintf(stderr, "- Is recipient ready and online?\n"); fprintf(stderr, "- If all else fails, cycle the power!\n"); exit(1); } /* hostname[8] = '\0'; */ #ifndef PLAN9 if (gethostname(hostname, sizeof(hostname)) < 0) { perror("gethostname"); exit(1); } #endif /* if ((hnend = strchr(hostname, '.')) != NULL) *hnend = '\0'; */ if (statflag) { checkqueue(printerfd); } else if (killflag) { killjob(printerfd); } else { sendjob(inputfd, printerfd); } exit(0); }