diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/fax |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/fax')
-rwxr-xr-x | sys/src/cmd/fax/fax2modem.c | 119 | ||||
-rwxr-xr-x | sys/src/cmd/fax/fax2receive.c | 193 | ||||
-rwxr-xr-x | sys/src/cmd/fax/fax2send.c | 171 | ||||
-rwxr-xr-x | sys/src/cmd/fax/file.c | 164 | ||||
-rwxr-xr-x | sys/src/cmd/fax/mkfile | 45 | ||||
-rwxr-xr-x | sys/src/cmd/fax/modem.c | 220 | ||||
-rwxr-xr-x | sys/src/cmd/fax/modem.h | 107 | ||||
-rwxr-xr-x | sys/src/cmd/fax/receive.c | 73 | ||||
-rwxr-xr-x | sys/src/cmd/fax/receiverc | 58 | ||||
-rwxr-xr-x | sys/src/cmd/fax/send.c | 55 | ||||
-rwxr-xr-x | sys/src/cmd/fax/subr.c | 71 |
11 files changed, 1276 insertions, 0 deletions
diff --git a/sys/src/cmd/fax/fax2modem.c b/sys/src/cmd/fax/fax2modem.c new file mode 100755 index 000000000..00640ab49 --- /dev/null +++ b/sys/src/cmd/fax/fax2modem.c @@ -0,0 +1,119 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +int +initfaxmodem(Modem *m) +{ + m->fax = 1; + m->phase = 'A'; + m->valid = 0; + + return Eok; +} + +static int +parameters(long a[], char *s) +{ + char *p; + int i; + + i = 0; + if((p = strchr(s, ':')) == 0) + return 0; + p++; + while(s = strchr(p, ',')){ + a[i++] = strtol(p, 0, 10); + p = s+1; + } + if(p) + a[i++] = strtol(p, 0, 10); + + return i; +} + +int +fcon(Modem *m) +{ + verbose("fcon: %s", m->response); + if(m->fax == 0 || m->phase != 'A') + return Rrerror; + m->phase = 'B'; + return Rcontinue; +} + +int +ftsi(Modem *m) +{ + char *p, *q; + + verbose("ftsi: %s", m->response); + if((p = strchr(m->response, '"')) == 0 || (q = strrchr(p+1, '"')) == 0) + return Rrerror; + while(*++p == ' ') + ; + *q = 0; + if((m->valid & Vftsi) == 0){ + strncpy(m->ftsi, p, sizeof(m->ftsi)-1); + m->valid |= Vftsi; + } + return Rcontinue; +} + +int +fdcs(Modem *m) +{ + verbose("fdcs: %s", m->response); + parameters(m->fdcs, m->response); + m->valid |= Vfdcs; + return Rcontinue; +} + +int +fcfr(Modem *m) +{ + verbose("fcfr: %s", m->response); + if(m->fax == 0) + return Rrerror; + /* ???? */ + return Rcontinue; +} + +int +fpts(Modem *m) +{ + verbose("fpts: %s", m->response); + if(m->fax == 0) + return Rrerror; + parameters(m->fpts, m->response); + m->valid |= Vfpts; + return Rcontinue; +} + +int +fet(Modem *m) +{ + char *p; + + verbose("fet: %s", m->response); + if(m->fax == 0 || (p = strchr(m->response, ':')) == 0) + return Rrerror; + m->fet = strtol(p+1, 0, 10); + m->valid |= Vfet; + return Rcontinue; +} + +int +fhng(Modem *m) +{ + char *p; + + verbose("fhng: %s", m->response); + if(m->fax == 0 || (p = strchr(m->response, ':')) == 0) + return Rrerror; + m->fhng = strtol(p+1, 0, 10); + m->valid |= Vfhng; + return Rhangup; +} diff --git a/sys/src/cmd/fax/fax2receive.c b/sys/src/cmd/fax/fax2receive.c new file mode 100755 index 000000000..e3c905a18 --- /dev/null +++ b/sys/src/cmd/fax/fax2receive.c @@ -0,0 +1,193 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +static char buf[102400]; + +static int +page(Modem *m, char *spool) +{ + int count, r; + char c; + + /* + * Start data reception. We should receive CONNECT in response + * to +FDR, then data reception starts when we send DC2. + */ + m->valid &= ~(Vfhng|Vfet|Vfpts); + if(command(m, "AT+FDR") != Eok) + return Esys; + + switch(response(m, 30)){ + + case Rconnect: + m->phase = 'C'; + if((r = createfaxfile(m, spool)) != Eok) + return r; + if((r = putmchar(m, "\022")) != Eok) + return r; + break; + + case Rhangup: + return Eok; + + default: + return seterror(m, Eattn); + } + + /* + * Receive data. + */ + verbose("starting page %d", m->pageno); + count = 0; + while((r = getmchar(m, &c, 6)) == Eok){ + if(c == '\020'){ + if((r = getmchar(m, &c, 3)) != Eok) + break; + if(c == '\003') + break; + if(c != '\020'){ + verbose("B%2.2ux", c); + continue; + } + } + buf[count++] = c; + if(count >= sizeof(buf)){ + if(write(m->pagefd, buf, count) < 0){ + close(m->pagefd); + return seterror(m, Esys); + } + count = 0; + } + } + verbose("page %d done, count %d", m->pageno, count); + if(count && write(m->pagefd, buf, count) < 0){ + close(m->pagefd); + return seterror(m, Esys); + } + if(r != Eok) + return r; + + /* + * Wait for either OK or ERROR. + */ + switch(r = response(m, 20)){ + + case Rok: + case Rrerror: + return Eok; + + default: + verbose("page: response %d", r); + return Eproto; + } +} + +static int +receive(Modem *m, char *spool) +{ + int r; + + loop: + switch(r = page(m, spool)){ + + case Eok: + /* + * Check we have a valid page reponse. + */ + if((m->valid & Vfhng) == 0 && (m->valid & (Vfet|Vfpts)) != (Vfet|Vfpts)){ + verbose("receive: invalid page reponse: #%4.4ux", m->valid); + return seterror(m, Eproto); + } + + /* + * Was the page successfully received? + * If not, try again. + */ + if((m->valid & Vfpts) && m->fpts[0] != 1) + goto loop; + + /* + * Another page of the same document, a new document + * or no more pages. + * If no more pages we still have to get the FHNG, so + * the code is just the same as if there was another + * page. + */ + if(m->valid & Vfet){ + switch(m->fet){ + + case 0: /* another page */ + case 2: /* no more pages */ + m->pageno++; + goto loop; + + case 1: /* new document */ + /* + * Bug: currently no way to run the + * fax-received process for this, so it + * just stays queued. + */ + faxrlog(m, Eok); + m->pageno = 1; + m->time = time(0); + m->pid = getpid(); + goto loop; + } + + verbose("receive: invalid FET: %d", m->fet); + return seterror(m, Eproto); + } + + /* + * All done or hangup error. + * On error remove all pages in the current document. + * Yik. + */ + if(m->valid & Vfhng){ + if(m->fhng == 0) + return Eok; + verbose("receive: FHNG: %d", m->fhng); + /* + for(r = 1; r <= m->pageno; r++){ + char pageid[128]; + + setpageid(pageid, spool, m->time, m->pid, r); + remove(pageid); + } + */ + return seterror(m, Eattn); + } + /*FALLTHROUGH*/ + + default: + return r; + } +} + +int +faxreceive(Modem *m, char *spool) +{ + int r; + + verbose("faxdaemon"); + if((r = initfaxmodem(m)) != Eok) + return r; + + /* + * assume that the phone has been answered and + * we have received +FCON + */ + m->pageno = 1; + m->time = time(0); + m->pid = getpid(); + fcon(m); + + /* + * I wish I knew how to set the default parameters on the + * MT1432 modem (+FIP in Class 2.0). + */ + return receive(m, spool); +} diff --git a/sys/src/cmd/fax/fax2send.c b/sys/src/cmd/fax/fax2send.c new file mode 100755 index 000000000..af97f33a3 --- /dev/null +++ b/sys/src/cmd/fax/fax2send.c @@ -0,0 +1,171 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +int +faxsend(Modem *m, int argc, char *argv[]) +{ + int c, count, r, flow; + char buf[128]; + + verbose("faxsend"); + if((r = initfaxmodem(m)) != Eok) + return r; + + /* telco just does the dialing */ + r = response(m, 120); + switch(r){ + case Rok: + break; + default: + r = seterror(m, Enoanswer); + return r; + + } + + xonoff(m, 1); + verbose("sending"); + m->pageno = 1; + while(argc--){ + if(m->pageno != 1) + sleep(1000); /* let the paper catch up */ + + m->valid &= ~(Vfhng|Vfet|Vfpts|Vftsi|Vfdcs); + if((r = openfaxfile(m, *argv)) != Eok) + return r; + + verbose("sending geometry"); + sprint(buf, "AT+FDT=%ld,%ld,%ld,%ld", m->df, m->vr, m->wd, m->ln); + if(command(m, buf) != Eok) + goto buggery; + if(response(m, 20) != Rconnect){ + r = seterror(m, Eincompatible); + goto buggery; + } + + /* + * Write the data, stuffing DLE's. + * After each bufferfull check if the remote + * sent us anything, e.g. CAN to abort. + * This also flushes out the ^S/^Q characters + * which the driver insists on sending us. + * (Could fix the driver, of course...). + */ + verbose("sending data"); + for(;;){ + flow = 0; + count = 0; + c = 0; + while(count < sizeof(buf)-1){ + if((c = Bgetc(m->bp)) < 0) + break; + buf[count++] = c; + if(c == '\020') + buf[count++] = c; + } + verbose("sending %d bytes", count); + if(count && write(m->fd, buf, count) < 0){ + verbose("write failed: %r"); + r = seterror(m, Esys); + goto buggery; + } + /* + * this does really rough flow control since the + * avanstar is even worse + */ + verbose("flow control"); + while((r = rawmchar(m, buf)) == Eok || flow){ + if(r != Eok){ + if(flow-- == 0) + break; + sleep(250); + continue; + } + switch(buf[0]){ + case '\030': + verbose("%c", buf[0]); + if(write(m->fd, "\020\003", 2) < 0){ + r = seterror(m, Esys); + goto buggery; + } + goto okexit; + case '\021': + flow = 0; + break; + case '\023': + flow = 4; + break; + case '\n': + break; + default: + verbose("%c", buf[0]); + r = seterror(m, Eproto); + goto buggery; + + } + } + if(c < 0) + break; + } + + + /* + * End of page, send DLE+ETX, + * get OK in response. + */ + verbose("sending end of page"); + if(write(m->fd, "\020\003", 2) < 0){ + r = seterror(m, Esys); + goto buggery; + } + verbose("waiting for OK"); + if(response(m, 120) != Rok){ + r = seterror(m, Enoresponse); + goto buggery; + } + + /* + * Did you hear me? - IT'S THE END OF THE PAGE. + * Argument is 0 if more pages to follow. + * Should get back an FPTS with an indication + * as to whether the page was successfully + * transmitted or not. + */ + sprint(buf, "AT+FET=%d", argc == 0? 2: 0); + if(command(m, buf) != Eok) + goto buggery; + switch(response(m, 20)){ + case Rok: + break; + case Rhangup: + if(m->fhng == 0 && argc == 0) + break; + r = seterror(m, Eproto); + goto buggery; + default: + r = seterror(m, Enoresponse); + goto buggery; + } + + if((m->valid & Vfpts) == 0 || m->fpts[0] != 1){ + r = seterror(m, Eproto); + goto buggery; + } + + Bterm(m->bp); + m->pageno++; + argv++; + } +okexit: + xonoff(m, 0); + return Eok; + +buggery: + xonoff(m, 0); + Bterm(m->bp); + command(m, "AT+FK"); + response(m, 5); + return r; +} diff --git a/sys/src/cmd/fax/file.c b/sys/src/cmd/fax/file.c new file mode 100755 index 000000000..3da7c7a96 --- /dev/null +++ b/sys/src/cmd/fax/file.c @@ -0,0 +1,164 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +static long wd[5] = { + 1728, 2048, 2432, 1216, 864 +}; + +void +setpageid(char *pageid, char *spool, long time, int pid, int pageno) +{ + sprint(pageid, "%s/%lud.%d.%3.3d", spool, time, pid, pageno); +} + +int +createfaxfile(Modem *m, char *spool) +{ + setpageid(m->pageid, spool, m->time, m->pid, m->pageno); + verbose("openfaxfile: %s", m->pageid); + if((m->pagefd = create(m->pageid, OTRUNC|OWRITE, 0666)) < 0) + return seterror(m, Esys); + + fprint(m->pagefd, "TYPE=ccitt-g31\n"); + fprint(m->pagefd, "WINDOW=0 0 %ld -1\n", wd[m->fdcs[2]]); + if(m->valid & Vftsi) + fprint(m->pagefd, "FTSI=%s\n", m->ftsi); + fprint(m->pagefd, "FDCS=%lud,%lud,%lud,%lud,%lud,%lud,%lud,%lud\n", + m->fdcs[0], m->fdcs[1], m->fdcs[2], m->fdcs[3], + m->fdcs[4], m->fdcs[5], m->fdcs[6], m->fdcs[7]); + fprint(m->pagefd, "\n"); + + return Eok; +} + +enum +{ + Gshdrsize= 0x40, +}; + +int +gsopen(Modem *m) +{ + int n; + char bytes[Gshdrsize]; + + /* + * Is this gs output + */ + n = Bread(m->bp, bytes, Gshdrsize); + if(n != Gshdrsize) + return seterror(m, Esys); + if(bytes[0]!='\0' || strcmp(bytes+1, "PC Research, Inc")!=0){ + Bseek(m->bp, 0, 0); + return seterror(m, Esys); + } + + m->valid |= Vtype; + if(bytes[0x1d]) + m->vr = 1; + else + m->vr = 0; + m->wd = 0; + m->ln = 2; + m->df = 0; + return Eok; +} + +int +picopen(Modem *m) +{ + char *p, *q; + int i, x; + + /* + * Look at the header. Every page should have a valid type. + * The first page should have WINDOW. + */ + while(p = Brdline(m->bp, '\n')){ + if(Blinelen(m->bp) == 1) + break; + p[Blinelen(m->bp)-1] = 0; + + verbose("openfaxfile: %s", p); + if(strcmp("TYPE=ccitt-g31", p) == 0) + m->valid |= Vtype; + /* + else if(m->pageno == 1 && strncmp("PHONE=", p, 6) == 0){ + strcpy(m->number, p+6); + m->valid |= Vphone; + } + */ + else if(m->pageno == 1 && strncmp("WINDOW=", p, 7) == 0){ + p += 7; + verbose("openfaxfile: WINDOW: %s", p); + for(i = 0; i < 4; i++){ + x = strtol(p, &q, 10); + if(i == 2) + m->wd = x; + if((p = q) == 0){ + Bterm(m->bp); + return seterror(m, Eproto); + } + } + for(i = 0; i < 5; i++){ + if(m->wd == wd[i]){ + m->wd = i; + m->valid |= Vwd; + break; + } + } + if((m->valid & Vwd) == 0){ + Bterm(m->bp); + return seterror(m, Eproto); + } + } + else if(m->pageno == 1 && strncmp("FDCS=", p, 5) == 0){ + p += 5; + m->df = m->vr = m->wd = 0; + m->ln = 2; + for(i = 0; i < 5; i++){ + x = strtol(p, &q, 10); + switch(i){ + case 0: + m->vr = x; + break; + case 3: + m->ln = x; + break; + case 4: + m->df = x; + break; + } + if((p = q) == 0){ + Bterm(m->bp); + return seterror(m, Eproto); + } + if(*p++ != ',') + break; + } + } + } + + verbose("openfaxfile: valid #%4.4ux", m->valid); + if((m->valid & (Vtype|Vwd)) != (Vtype|Vwd)){ + Bterm(m->bp); + return seterror(m, Eproto); + } + + return Eok; +} + +int +openfaxfile(Modem *m, char *file) +{ + if((m->bp = Bopen(file, OREAD)) == 0) + return seterror(m, Esys); + m->valid &= ~(Vtype); + + if(gsopen(m) == Eok) + return Eok; + return picopen(m); +} diff --git a/sys/src/cmd/fax/mkfile b/sys/src/cmd/fax/mkfile new file mode 100755 index 000000000..050228627 --- /dev/null +++ b/sys/src/cmd/fax/mkfile @@ -0,0 +1,45 @@ +</$objtype/mkfile + +TARG = faxreceive\ + faxsend\ + +OFILES=\ + fax2modem.$O\ + file.$O\ + modem.$O\ + subr.$O\ + +RECEIVE=\ + $OFILES\ + receive.$O\ + fax2receive.$O\ + +SEND=\ + $OFILES\ + send.$O\ + fax2send.$O\ + +BIN=/$objtype/bin/aux + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + receive.c\ + send.c\ + fax2receive.c\ + fax2send.c\ + ${TARG:%=%.c}\ + ${TARG:%=/386/bin/%}\ + +</sys/src/cmd/mkmany + +$O.faxreceive: $RECEIVE + $LD -o $target $prereq + +$O.faxsend: $SEND + $LD -o $target $prereq + +install.rc:V: + mkdir /sys/lib/fax + cp receiverc /sys/lib/fax diff --git a/sys/src/cmd/fax/modem.c b/sys/src/cmd/fax/modem.c new file mode 100755 index 000000000..d0decc3e7 --- /dev/null +++ b/sys/src/cmd/fax/modem.c @@ -0,0 +1,220 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +typedef struct { + char *terse; + char *verbose; + int result; + int (*f)(Modem*); +} ResultCode; + +static ResultCode results[] = { + { "0", "OK", Rok, 0, }, + { "1", "CONNECT", Rconnect, 0, }, + { "2", "RING", Rring, 0, }, + { "3", "NO CARRIER", Rfailure, 0, }, + { "4", "ERROR", Rrerror, 0, }, + { "5", "CONNECT 1200", Rconnect, 0, }, + { "6", "NO DIALTONE", Rfailure, 0, }, + { "7", "BUSY", Rfailure, 0, }, + { "8", "NO ANSWER", Rfailure, 0, }, + { "9", "CONNECT 2400", Rconnect, 0, }, /* MT1432BA */ + { "10", "CONNECT 2400", Rconnect, 0, }, /* Hayes */ + { "11", "CONNECT 4800", Rconnect, 0, }, + { "12", "CONNECT 9600", Rconnect, 0, }, + { "13", "CONNECT 14400",Rconnect, 0, }, + { "23", "CONNECT 1275", Rconnect, 0, }, /* MT1432BA */ + + { "-1", "+FCON", Rcontinue, fcon, }, + { "-1", "+FTSI", Rcontinue, ftsi, }, + { "-1", "+FDCS", Rcontinue, fdcs, }, + { "-1", "+FCFR", Rcontinue, fcfr, }, + { "-1", "+FPTS", Rcontinue, fpts, }, + { "-1", "+FET", Rcontinue, fet, }, + { "-1", "+FHNG", Rcontinue, fhng, }, + + { 0 }, +}; + +void +initmodem(Modem *m, int fd, int cfd, char *type, char *id) +{ + m->fd = fd; + m->cfd = cfd; + if(id == 0) + id = "Plan 9"; + m->id = id; + m->t = type; +} + +int +rawmchar(Modem *m, char *p) +{ + Dir *d; + int n; + + if(m->icount == 0) + m->iptr = m->ibuf; + + if(m->icount){ + *p = *m->iptr++; + m->icount--; + return Eok; + } + + m->iptr = m->ibuf; + + if((d = dirfstat(m->fd)) == nil){ + verbose("rawmchar: dirfstat: %r"); + return seterror(m, Esys); + } + n = d->length; + free(d); + if(n == 0) + return Enoresponse; + + if(n > sizeof(m->ibuf)-1) + n = sizeof(m->ibuf)-1; + if((m->icount = read(m->fd, m->ibuf, n)) <= 0){ + verbose("rawmchar: read: %r"); + m->icount = 0; + return seterror(m, Esys); + } + *p = *m->iptr++; + m->icount--; + + return Eok; +} + +int +getmchar(Modem *m, char *buf, long timeout) +{ + int r, t; + + timeout += time(0); + while((t = time(0)) <= timeout){ + switch(r = rawmchar(m, buf)){ + + case Eok: + return Eok; + + case Enoresponse: + sleep(100); + continue; + + default: + return r; + } + } + verbose("getmchar: time %ud, timeout %ud", t, timeout); + + return seterror(m, Enoresponse); +} + +int +putmchar(Modem *m, char *p) +{ + if(write(m->fd, p, 1) < 0) + return seterror(m, Esys); + return Eok; +} + +/* + * lines terminate with cr-lf + */ +static int +getmline(Modem *m, char *buf, int len, long timeout) +{ + int r, t; + char *e = buf+len-1; + char last = 0; + + timeout += time(0); + while((t = time(0)) <= timeout){ + switch(r = rawmchar(m, buf)){ + + case Eok: + /* ignore ^s ^q which are used for flow */ + if(*buf == '\021' || *buf == '\023') + continue; + if(*buf == '\n'){ + /* ignore nl if its not with a cr */ + if(last == '\r'){ + *buf = 0; + return Eok; + } + continue; + } + last = *buf; + if(*buf == '\r') + continue; + buf++; + if(buf == e){ + *buf = 0; + return Eok; + } + continue; + + case Enoresponse: + sleep(100); + continue; + + default: + return r; + } + } + verbose("getmline: time %ud, timeout %ud", t, timeout); + + return seterror(m, Enoresponse); +} + +int +command(Modem *m, char *s) +{ + verbose("m->: %s", s); + if(fprint(m->fd, "%s\r", s) < 0) + return seterror(m, Esys); + return Eok; +} + +/* + * Read till we see a message or we time out. + * BUG: line lengths not checked; + * newlines + */ +int +response(Modem *m, int timeout) +{ + int r; + ResultCode *rp; + + while(getmline(m, m->response, sizeof(m->response), timeout) == Eok){ + if(m->response[0] == 0) + continue; + verbose("<-m: %s", m->response); + for(rp = results; rp->terse; rp++){ + if(strncmp(rp->verbose, m->response, strlen(rp->verbose))) + continue; + r = rp->result; + if(rp->f && (r = (*rp->f)(m)) == Rcontinue) + break; + return r; + } + } + + m->response[0] = 0; + return Rnoise; +} + +void +xonoff(Modem *m, int i) +{ + char buf[8]; + + sprint(buf, "x%d", i); + i = strlen(buf); + write(m->cfd, buf, i); +} diff --git a/sys/src/cmd/fax/modem.h b/sys/src/cmd/fax/modem.h new file mode 100755 index 000000000..2b5ca17ff --- /dev/null +++ b/sys/src/cmd/fax/modem.h @@ -0,0 +1,107 @@ +typedef struct { + char *t; + int fd; + int cfd; + char *id; + char response[128]; + char error[128]; + + int fax; + char phase; + char ftsi[128]; /* remote ID */ + long fdcs[8]; /* frame information */ + long fpts[8]; /* page reception response */ + long fet; /* post page message */ + long fhng; /* call termination status */ + int pageno; /* current page number */ + char pageid[128]; /* current page file */ + int pagefd; /* current page fd */ + int valid; /* valid page responses */ + long time; /* timestamp */ + int pid; + + char ibuf[1024]; /* modem input buffering */ + char *iptr; + long icount; + + Biobuf *bp; /* file input buffering */ + + /* FDCS parameters */ + long wd; /* width */ + long vr; /* resolution */ + long ln; /* page size (length) */ + long df; /* huffman encoding */ +} Modem; + +enum { /* ResultCodes */ + Rok = 0, + Rconnect, + Rring, + Rfailure, + Rrerror, + Rcontinue, + Rhangup, + Rnoise, +}; + +enum { /* ErrorCodes */ + Eok = 0, /* no error */ + Eattn, /* can't get modem's attention */ + Enoresponse, /* no response from modem */ + Enoanswer, /* no answer from other side */ + Enofax, /* other side isn't a fax machine */ + Eincompatible, /* transmission incompatible with receiver */ + Esys, /* system call error */ + Eproto, /* fax protocol botch */ +}; + +enum { /* things that are valid */ + Vfdcs = 0x0001, /* page responses */ + Vftsi = 0x0002, + Vfpts = 0x0004, + Vfet = 0x0008, + Vfhng = 0x0010, + + Vwd = 0x4000, + Vtype = 0x8000, +}; + +/* fax2modem.c */ +extern int initfaxmodem(Modem*); +extern int fcon(Modem*); +extern int ftsi(Modem*); +extern int fdcs(Modem*); +extern int fcfr(Modem*); +extern int fpts(Modem*); +extern int fet(Modem*); +extern int fhng(Modem*); + +/* fax2receive.c */ +extern int faxreceive(Modem*, char*); + +/* fax2send.c */ +extern int faxsend(Modem*, int, char*[]); + +/* modem.c */ +extern int setflow(Modem*, int); +extern int setspeed(Modem*, int); +extern int rawmchar(Modem*, char*); +extern int getmchar(Modem*, char*, long); +extern int putmchar(Modem*, char*); +extern int command(Modem*, char*); +extern int response(Modem*, int); +extern void initmodem(Modem*, int, int, char*, char*); +extern void xonoff(Modem*, int); + +/* spool.c */ +extern void setpageid(char*, char*, long, int, int); +extern int createfaxfile(Modem*, char*); +extern int openfaxfile(Modem*, char*); + +/* subr.c */ +extern void verbose(char*, ...); +extern void error(char*, ...); +extern int seterror(Modem*, int); +extern void faxrlog(Modem*, int); +extern void faxxlog(Modem*, int); +extern int vflag; diff --git a/sys/src/cmd/fax/receive.c b/sys/src/cmd/fax/receive.c new file mode 100755 index 000000000..ece399f9f --- /dev/null +++ b/sys/src/cmd/fax/receive.c @@ -0,0 +1,73 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +static Modem modems[1]; + +static char *spool = "/mail/faxqueue"; +static char *type = "default"; +static char *receiverc = "/sys/lib/fax/receiverc"; + +static void +receivedone(Modem *m, int ok) +{ + char *argv[10], *p, time[16], pages[16]; + int argc; + + faxrlog(m, ok); + if(ok != Eok) + return; + + argc = 0; + if(p = strrchr(receiverc, '/')) + argv[argc++] = p+1; + else + argv[argc++] = receiverc; + sprint(time, "%lud.%d", m->time, m->pid); + argv[argc++] = time; + argv[argc++] = "Y"; + sprint(pages, "%d", m->pageno-1); + argv[argc++] = pages; + if(m->valid & Vftsi) + argv[argc++] = m->ftsi; + argv[argc] = 0; + exec(receiverc, argv); + exits("can't exec"); +} + +static void +usage(void) +{ + fprint(2, "%s: usage: %s [-v] [-s dir]\n", argv0, argv0); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + Modem *m; + + m = &modems[0]; + + ARGBEGIN{ + case 'v': + vflag = 1; + break; + + case 's': + spool = ARGF(); + break; + + default: + usage(); + break; + + }ARGEND + + initmodem(m, 0, -1, type, 0); + receivedone(m, faxreceive(m, spool)); + + exits(0); +} diff --git a/sys/src/cmd/fax/receiverc b/sys/src/cmd/fax/receiverc new file mode 100755 index 000000000..6cc56a3cc --- /dev/null +++ b/sys/src/cmd/fax/receiverc @@ -0,0 +1,58 @@ +#!/bin/rc +spool=/mail/faxqueue +recipients=/mail/faxqueue/faxrecipients + +# run mail as if we're on fs +rm /srv/fs +9fs fs +bind -c /n/fs/mail/faxqueue /mail/faxqueue + +# +# Arguments should be +# time Y|N pages [ftsi] +# +switch($#*){ + +case 4 + # + # Check for the NYT. It's 9 pages from 'Via Fax '. + # + nyt=false + if(~ $2 Y && {~ $4 'Via Fax '}){ + switch(`{date|sed 's/ .*//'}){ + case Mon Tue Wed Thu Fri + hour=`{date|sed 's/.* ([0-9][0-9]):.*/\1/'} + if(test $3 -gt 7 -a '(' $hour -lt 7 -o $hour -ge 21 ')') + nyt=true + case * + if(test $3 -gt 7) + nyt=true + } + } + switch($nyt){ + + case true + to=`{seq 0 1 $3} + for(i in `{seq 2 1 $3}){ + switch($i){ + + case ? + ext=00$i + case ?? + ext=0$i + case ??? + ext=$i + } + cp $spool/$1.$ext /n/fs/lib/nyt/nyt.$to($i) + } + cp $spool/$1.1 /n/fs/lib/nyt/nyt.$3 + rm -f $spool/$1.* + case * + {echo $*; echo FAX: page -w $spool/$1.'*'} | mail `{cat $recipients} + } +case 3 + {echo $*; echo FAX: page -w $spool/$1.'*'} | mail `{cat $recipients} +case * + {echo $*; echo FAX: page -w $spool/$1.'*'} | mail postmaster +} +exit 0 diff --git a/sys/src/cmd/fax/send.c b/sys/src/cmd/fax/send.c new file mode 100755 index 000000000..9fa7342f6 --- /dev/null +++ b/sys/src/cmd/fax/send.c @@ -0,0 +1,55 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +static Modem modems[1]; + +static void +usage(void) +{ + fprint(2, "%s: usage: %s [-v] number pages\n", argv0, argv0); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + int fd, cfd, r; + Modem *m; + char *addr; + + m = &modems[0]; + + ARGBEGIN{ + case 'v': + vflag = 1; + break; + default: + usage(); + break; + + }ARGEND + + if(argc <= 1) + usage(); + verbose("send: %s %s...", argv[0], argv[1]); + + addr = netmkaddr(*argv, "telco", "fax!9600"); + fd = dial(addr, 0, 0, &cfd); + if(fd < 0){ + fprint(2, "faxsend: can't dial %s: %r\n", addr); + exits("Retry, can't dial"); + } + initmodem(m, fd, cfd, 0, 0); + argc--; argv++; + r = faxsend(m, argc, argv); + if(r != Eok){ + fprint(2, "faxsend: %s\n", m->error); + syslog(0, "fax", "failed %s %s: %s", argv[0], argv[1], m->error); + exits(m->error); + } + syslog(0, "fax", "success %s %s", argv[0], argv[1]); + exits(0); +} diff --git a/sys/src/cmd/fax/subr.c b/sys/src/cmd/fax/subr.c new file mode 100755 index 000000000..20248d0a5 --- /dev/null +++ b/sys/src/cmd/fax/subr.c @@ -0,0 +1,71 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "modem.h" + +int vflag; + +void +verbose(char *fmt, ...) +{ + va_list arg; + char buf[512]; + + if(vflag){ + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + syslog(0, "fax", buf); + } +} + +void +error(char *fmt, ...) +{ + va_list arg; + char buf[512]; + int n; + + n = sprint(buf, "%s: ", argv0); + va_start(arg, fmt); + vseprint(buf+n, buf+sizeof(buf)-n, fmt, arg); + va_end(arg); + fprint(2, buf); + if(vflag) + print(buf+n); + exits("error"); +} + +static char *errors[] = { + [Eok] "no error", + [Eattn] "can't get modem's attention", + [Enoanswer] "Retry, no answer or busy", + [Enoresponse] "Retry, no response from modem", + [Eincompatible] "Retry, incompatible", + [Esys] "Retry, system call error", + [Eproto] "Retry, fax protocol botch", +}; + +int +seterror(Modem *m, int error) +{ + if(error == Esys) + sprint(m->error, "%s: %r", errors[Esys]); + else + strcpy(m->error, errors[error]); + verbose("seterror: %s", m->error); + return error; +} + +void +faxrlog(Modem *m, int ok) +{ + char buf[1024]; + int n; + + n = sprint(buf, "receive %lud %c %d", m->time, ok == Eok ? 'Y': 'N', m->pageno-1); + if(ok == Eok && (m->valid & Vftsi)) + sprint(buf+n, " %s", m->ftsi); + syslog(0, "fax", buf); +} |