| #include <u.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <sys/stat.h> |
| #include <sys/param.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <signal.h> |
| #include <libc.h> |
| |
| #define REDIALTIMEOUT 15 |
| #define TIMEOUT 600 |
| |
| char tmpfilename[L_tmpnam+1]; |
| int alarmstate = 0; |
| int debugflag = 0; |
| int killflag = 0; |
| int statflag = 0; |
| |
| 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, long tosend) { |
| int n; |
| int sent = 0; |
| int percent = 0; |
| |
| if (debugflag) |
| fprintf(stderr, "lpdsend: copyfile(%d,%d,%ld)\n", |
| in, out, tosend); |
| while ((n=read(in, sendbuf, SBSIZE)) > 0) { |
| if (debugflag) |
| fprintf(stderr, "lpdsend: copyfile read %d bytes from %d\n", |
| n, in); |
| alarm(TIMEOUT); alarmstate = 1; |
| if (write(out, sendbuf, n) != n) { |
| alarm(0); |
| fprintf(stderr, "write to fd %d failed\n", out); |
| return(0); |
| } |
| alarm(0); |
| if (debugflag) |
| fprintf(stderr, "lpdsend: copyfile wrote %d bytes to %d\n", |
| n, out); |
| sent += n; |
| if (tosend && ((sent*100/tosend)>=(percent+WARNPC))) { |
| percent += WARNPC; |
| fprintf(stderr, ": %5.2f%% sent\n", sent*100.0/tosend); |
| } |
| } |
| if (debugflag) |
| fprintf(stderr, "lpdsend: copyfile read %d bytes from %d\n", |
| n, in); |
| return(!n); |
| } |
| |
| char strbuf[120]; |
| char hostname[MAXHOSTNAMELEN], *username, *printername, *killarg; |
| char *inputname; |
| char filetype = 'o'; /* 'o' is for PostScript */ |
| int seqno = 0; |
| char *seqfilename; |
| |
| 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, 0L); |
| } |
| |
| void |
| checkqueue(int printerfd) { |
| int strlength; |
| |
| 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, 0L); |
| /* |
| { int n; |
| unsigned char sendbuf[1]; |
| 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, long size) { |
| int strlength; |
| |
| sprintf(strbuf, "%c%ld 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, "%ld 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, "%ld bytes sent, status: end of job\n", (long)statbuf.st_size); |
| } |
| |
| /* |
| * make an address, add the defaults |
| */ |
| char * |
| netmkaddr(char *linear, char *defnet, char *defsrv) |
| { |
| static char addr[512]; |
| char *cp; |
| |
| /* |
| * dump network name |
| */ |
| cp = strchr(linear, '!'); |
| if(cp == 0){ |
| if(defnet==0){ |
| if(defsrv) |
| sprintf(addr, "net!%s!%s", linear, defsrv); |
| else |
| sprintf(addr, "net!%s", linear); |
| } |
| else { |
| if(defsrv) |
| sprintf(addr, "%s!%s!%s", defnet, linear, defsrv); |
| else |
| sprintf(addr, "%s!%s", defnet, linear); |
| } |
| return addr; |
| } |
| |
| /* |
| * if there is already a service, use it |
| */ |
| cp = strchr(cp+1, '!'); |
| if(cp) |
| return linear; |
| |
| /* |
| * add default service |
| */ |
| if(defsrv == 0) |
| return linear; |
| sprintf(addr, "%s!%s", linear, defsrv); |
| |
| return addr; |
| } |
| |
| void |
| main(int argc, char *argv[]) { |
| int c, usgflg = 0; |
| char *desthostname; |
| int printerfd; |
| int inputfd; |
| int sendport; |
| char portstr[4]; |
| |
| desthostname = nil; |
| if (signal(SIGALRM, alarmhandler) == SIG_ERR) { |
| fprintf(stderr, "failed to set alarm handler\n"); |
| exit(1); |
| } |
| while ((c = getopt(argc, argv, "Dd:k:qs:t: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 's': |
| seqno = strtol(optarg, NULL, 10); |
| if (seqno < 0 || seqno > 999) |
| seqno = 0; |
| 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 [-s seqno] [-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. |
| */ |
| inputfd = -1; |
| 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 = create(tmpfilename, ORDWR, 0600)) < 0) { |
| fprintf(stderr, "open(%s) failed\n", tmpfilename); |
| exit(1); |
| } |
| atexit(cleanup); |
| debug("copy input to temp file "); |
| debug(tmpfilename); |
| debug("\n"); |
| if (!copyfile(0, inputfd, 0L)) { |
| fprintf(stderr, "failed to copy file to temporary file\n"); |
| exit(1); |
| } |
| if (lseek(inputfd, 0L, 0) < 0) { |
| fprintf(stderr, "failed to seek back to the beginning of the temporary file\n"); |
| exit(1); |
| } |
| } |
| } |
| |
| sprintf(strbuf, "%s", netmkaddr(desthostname, "tcp", "printer")); |
| fprintf(stderr, "connecting to %s\n", strbuf); |
| 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 = dial(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 |
| /* char *hnend; |
| if ((hnend = strchr(hostname, '.')) != NULL) |
| *hnend = '\0'; |
| */ |
| if (statflag) { |
| checkqueue(printerfd); |
| } else if (killflag) { |
| killjob(printerfd); |
| } else { |
| sendjob(inputfd, printerfd); |
| } |
| exit(0); |
| } |