1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier
5219b2ee8SDavid du Colombier #include "modem.h"
6219b2ee8SDavid du Colombier
7219b2ee8SDavid du Colombier int
faxsend(Modem * m,int argc,char * argv[])8219b2ee8SDavid du Colombier faxsend(Modem *m, int argc, char *argv[])
9219b2ee8SDavid du Colombier {
107dd7cddfSDavid du Colombier int c, count, r, flow;
11219b2ee8SDavid du Colombier char buf[128];
12219b2ee8SDavid du Colombier
13219b2ee8SDavid du Colombier verbose("faxsend");
14219b2ee8SDavid du Colombier if((r = initfaxmodem(m)) != Eok)
15219b2ee8SDavid du Colombier return r;
16219b2ee8SDavid du Colombier
17219b2ee8SDavid du Colombier /* telco just does the dialing */
18219b2ee8SDavid du Colombier r = response(m, 120);
19219b2ee8SDavid du Colombier switch(r){
20219b2ee8SDavid du Colombier case Rok:
21219b2ee8SDavid du Colombier break;
22219b2ee8SDavid du Colombier default:
23219b2ee8SDavid du Colombier r = seterror(m, Enoanswer);
24219b2ee8SDavid du Colombier return r;
25219b2ee8SDavid du Colombier
26219b2ee8SDavid du Colombier }
27219b2ee8SDavid du Colombier
287dd7cddfSDavid du Colombier xonoff(m, 1);
297dd7cddfSDavid du Colombier verbose("sending");
30219b2ee8SDavid du Colombier m->pageno = 1;
31219b2ee8SDavid du Colombier while(argc--){
32219b2ee8SDavid du Colombier if(m->pageno != 1)
33219b2ee8SDavid du Colombier sleep(1000); /* let the paper catch up */
34219b2ee8SDavid du Colombier
35219b2ee8SDavid du Colombier m->valid &= ~(Vfhng|Vfet|Vfpts|Vftsi|Vfdcs);
36219b2ee8SDavid du Colombier if((r = openfaxfile(m, *argv)) != Eok)
37219b2ee8SDavid du Colombier return r;
38219b2ee8SDavid du Colombier
397dd7cddfSDavid du Colombier verbose("sending geometry");
407dd7cddfSDavid du Colombier sprint(buf, "AT+FDT=%ld,%ld,%ld,%ld", m->df, m->vr, m->wd, m->ln);
41219b2ee8SDavid du Colombier if(command(m, buf) != Eok)
42219b2ee8SDavid du Colombier goto buggery;
43219b2ee8SDavid du Colombier if(response(m, 20) != Rconnect){
44219b2ee8SDavid du Colombier r = seterror(m, Eincompatible);
45219b2ee8SDavid du Colombier goto buggery;
46219b2ee8SDavid du Colombier }
47219b2ee8SDavid du Colombier
48219b2ee8SDavid du Colombier /*
49219b2ee8SDavid du Colombier * Write the data, stuffing DLE's.
50219b2ee8SDavid du Colombier * After each bufferfull check if the remote
51219b2ee8SDavid du Colombier * sent us anything, e.g. CAN to abort.
52219b2ee8SDavid du Colombier * This also flushes out the ^S/^Q characters
53219b2ee8SDavid du Colombier * which the driver insists on sending us.
54219b2ee8SDavid du Colombier * (Could fix the driver, of course...).
55219b2ee8SDavid du Colombier */
567dd7cddfSDavid du Colombier verbose("sending data");
57219b2ee8SDavid du Colombier for(;;){
587dd7cddfSDavid du Colombier flow = 0;
59219b2ee8SDavid du Colombier count = 0;
60219b2ee8SDavid du Colombier c = 0;
61219b2ee8SDavid du Colombier while(count < sizeof(buf)-1){
627dd7cddfSDavid du Colombier if((c = Bgetc(m->bp)) < 0)
63219b2ee8SDavid du Colombier break;
64219b2ee8SDavid du Colombier buf[count++] = c;
65219b2ee8SDavid du Colombier if(c == '\020')
66219b2ee8SDavid du Colombier buf[count++] = c;
67219b2ee8SDavid du Colombier }
687dd7cddfSDavid du Colombier verbose("sending %d bytes", count);
69219b2ee8SDavid du Colombier if(count && write(m->fd, buf, count) < 0){
707dd7cddfSDavid du Colombier verbose("write failed: %r");
71219b2ee8SDavid du Colombier r = seterror(m, Esys);
72219b2ee8SDavid du Colombier goto buggery;
73219b2ee8SDavid du Colombier }
747dd7cddfSDavid du Colombier /*
757dd7cddfSDavid du Colombier * this does really rough flow control since the
767dd7cddfSDavid du Colombier * avanstar is even worse
777dd7cddfSDavid du Colombier */
787dd7cddfSDavid du Colombier verbose("flow control");
79*80ee5cbfSDavid du Colombier while((r = rawmchar(m, buf)) == Eok || flow){
807dd7cddfSDavid du Colombier if(r != Eok){
817dd7cddfSDavid du Colombier if(flow-- == 0)
82219b2ee8SDavid du Colombier break;
837dd7cddfSDavid du Colombier sleep(250);
847dd7cddfSDavid du Colombier continue;
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier switch(buf[0]){
877dd7cddfSDavid du Colombier case '\030':
88219b2ee8SDavid du Colombier verbose("%c", buf[0]);
89219b2ee8SDavid du Colombier if(write(m->fd, "\020\003", 2) < 0){
90219b2ee8SDavid du Colombier r = seterror(m, Esys);
91219b2ee8SDavid du Colombier goto buggery;
92219b2ee8SDavid du Colombier }
93219b2ee8SDavid du Colombier goto okexit;
947dd7cddfSDavid du Colombier case '\021':
957dd7cddfSDavid du Colombier flow = 0;
967dd7cddfSDavid du Colombier break;
977dd7cddfSDavid du Colombier case '\023':
987dd7cddfSDavid du Colombier flow = 4;
997dd7cddfSDavid du Colombier break;
1007dd7cddfSDavid du Colombier case '\n':
1017dd7cddfSDavid du Colombier break;
1027dd7cddfSDavid du Colombier default:
103219b2ee8SDavid du Colombier verbose("%c", buf[0]);
104219b2ee8SDavid du Colombier r = seterror(m, Eproto);
105219b2ee8SDavid du Colombier goto buggery;
1067dd7cddfSDavid du Colombier
107219b2ee8SDavid du Colombier }
108219b2ee8SDavid du Colombier }
1097dd7cddfSDavid du Colombier if(c < 0)
1107dd7cddfSDavid du Colombier break;
111219b2ee8SDavid du Colombier }
112219b2ee8SDavid du Colombier
1137dd7cddfSDavid du Colombier
114219b2ee8SDavid du Colombier /*
115219b2ee8SDavid du Colombier * End of page, send DLE+ETX,
116219b2ee8SDavid du Colombier * get OK in response.
117219b2ee8SDavid du Colombier */
1187dd7cddfSDavid du Colombier verbose("sending end of page");
119219b2ee8SDavid du Colombier if(write(m->fd, "\020\003", 2) < 0){
120219b2ee8SDavid du Colombier r = seterror(m, Esys);
121219b2ee8SDavid du Colombier goto buggery;
122219b2ee8SDavid du Colombier }
1237dd7cddfSDavid du Colombier verbose("waiting for OK");
1247dd7cddfSDavid du Colombier if(response(m, 120) != Rok){
125219b2ee8SDavid du Colombier r = seterror(m, Enoresponse);
126219b2ee8SDavid du Colombier goto buggery;
127219b2ee8SDavid du Colombier }
128219b2ee8SDavid du Colombier
129219b2ee8SDavid du Colombier /*
130219b2ee8SDavid du Colombier * Did you hear me? - IT'S THE END OF THE PAGE.
131219b2ee8SDavid du Colombier * Argument is 0 if more pages to follow.
132219b2ee8SDavid du Colombier * Should get back an FPTS with an indication
133219b2ee8SDavid du Colombier * as to whether the page was successfully
134219b2ee8SDavid du Colombier * transmitted or not.
135219b2ee8SDavid du Colombier */
136219b2ee8SDavid du Colombier sprint(buf, "AT+FET=%d", argc == 0? 2: 0);
137219b2ee8SDavid du Colombier if(command(m, buf) != Eok)
138219b2ee8SDavid du Colombier goto buggery;
139219b2ee8SDavid du Colombier switch(response(m, 20)){
140219b2ee8SDavid du Colombier case Rok:
141219b2ee8SDavid du Colombier break;
142219b2ee8SDavid du Colombier case Rhangup:
143219b2ee8SDavid du Colombier if(m->fhng == 0 && argc == 0)
144219b2ee8SDavid du Colombier break;
145219b2ee8SDavid du Colombier r = seterror(m, Eproto);
146219b2ee8SDavid du Colombier goto buggery;
147219b2ee8SDavid du Colombier default:
148219b2ee8SDavid du Colombier r = seterror(m, Enoresponse);
149219b2ee8SDavid du Colombier goto buggery;
150219b2ee8SDavid du Colombier }
151219b2ee8SDavid du Colombier
152219b2ee8SDavid du Colombier if((m->valid & Vfpts) == 0 || m->fpts[0] != 1){
153219b2ee8SDavid du Colombier r = seterror(m, Eproto);
154219b2ee8SDavid du Colombier goto buggery;
155219b2ee8SDavid du Colombier }
156219b2ee8SDavid du Colombier
157219b2ee8SDavid du Colombier Bterm(m->bp);
158219b2ee8SDavid du Colombier m->pageno++;
159219b2ee8SDavid du Colombier argv++;
160219b2ee8SDavid du Colombier }
161219b2ee8SDavid du Colombier okexit:
1627dd7cddfSDavid du Colombier xonoff(m, 0);
163219b2ee8SDavid du Colombier return Eok;
164219b2ee8SDavid du Colombier
165219b2ee8SDavid du Colombier buggery:
1667dd7cddfSDavid du Colombier xonoff(m, 0);
167219b2ee8SDavid du Colombier Bterm(m->bp);
168219b2ee8SDavid du Colombier command(m, "AT+FK");
169219b2ee8SDavid du Colombier response(m, 5);
170219b2ee8SDavid du Colombier return r;
171219b2ee8SDavid du Colombier }
172