xref: /plan9/sys/src/cmd/fax/fax2send.c (revision 80ee5cbfe36716af62da8896207e9763b8e3d760)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "modem.h"
6 
7 int
faxsend(Modem * m,int argc,char * argv[])8 faxsend(Modem *m, int argc, char *argv[])
9 {
10 	int c, count, r, flow;
11 	char buf[128];
12 
13 	verbose("faxsend");
14 	if((r = initfaxmodem(m)) != Eok)
15 		return r;
16 
17 	/* telco just does the dialing */
18 	r = response(m, 120);
19 	switch(r){
20 	case Rok:
21 		break;
22 	default:
23 		r = seterror(m, Enoanswer);
24 		return r;
25 
26 	}
27 
28 	xonoff(m, 1);
29 	verbose("sending");
30 	m->pageno = 1;
31 	while(argc--){
32 		if(m->pageno != 1)
33 			sleep(1000);	/* let the paper catch up */
34 
35 		m->valid &= ~(Vfhng|Vfet|Vfpts|Vftsi|Vfdcs);
36 		if((r = openfaxfile(m, *argv)) != Eok)
37 			return r;
38 
39 		verbose("sending geometry");
40 		sprint(buf, "AT+FDT=%ld,%ld,%ld,%ld", m->df, m->vr, m->wd, m->ln);
41 		if(command(m, buf) != Eok)
42 			goto buggery;
43 		if(response(m, 20) != Rconnect){
44 			r = seterror(m, Eincompatible);
45 			goto buggery;
46 		}
47 
48 		/*
49 		 * Write the data, stuffing DLE's.
50 		 * After each bufferfull check if the remote
51 		 * sent us anything, e.g. CAN to abort.
52 		 * This also flushes out the ^S/^Q characters
53 		 * which the driver insists on sending us.
54 		 * (Could fix the driver, of course...).
55 		 */
56 		verbose("sending data");
57 		for(;;){
58 			flow = 0;
59 			count = 0;
60 			c = 0;
61 			while(count < sizeof(buf)-1){
62 				if((c = Bgetc(m->bp)) < 0)
63 					break;
64 				buf[count++] = c;
65 				if(c == '\020')
66 					buf[count++] = c;
67 			}
68 			verbose("sending %d bytes", count);
69 			if(count && write(m->fd, buf, count) < 0){
70 				verbose("write failed: %r");
71 				r = seterror(m, Esys);
72 				goto buggery;
73 			}
74 			/*
75 			 *  this does really rough flow control since the
76 			 *  avanstar is even worse
77 			 */
78 			verbose("flow control");
79 			while((r = rawmchar(m, buf)) == Eok || flow){
80 				if(r != Eok){
81 					if(flow-- == 0)
82 						break;
83 					sleep(250);
84 					continue;
85 				}
86 				switch(buf[0]){
87 				case '\030':
88 					verbose("%c", buf[0]);
89 					if(write(m->fd, "\020\003", 2) < 0){
90 						r = seterror(m, Esys);
91 						goto buggery;
92 					}
93 					goto okexit;
94 				case '\021':
95 					flow = 0;
96 					break;
97 				case '\023':
98 					flow = 4;
99 					break;
100 				case '\n':
101 					break;
102 				default:
103 					verbose("%c", buf[0]);
104 					r = seterror(m, Eproto);
105 					goto buggery;
106 
107 				}
108 			}
109 			if(c < 0)
110 				break;
111 		}
112 
113 
114 		/*
115 		 * End of page, send DLE+ETX,
116 		 * get OK in response.
117 		 */
118 		verbose("sending end of page");
119 		if(write(m->fd, "\020\003", 2) < 0){
120 			r = seterror(m, Esys);
121 			goto buggery;
122 		}
123 		verbose("waiting for OK");
124 		if(response(m, 120) != Rok){
125 			r = seterror(m, Enoresponse);
126 			goto buggery;
127 		}
128 
129 		/*
130 		 * Did you hear me? - IT'S THE END OF THE PAGE.
131 		 * Argument is 0 if more pages to follow.
132 		 * Should get back an FPTS with an indication
133 		 * as to whether the page was successfully
134 		 * transmitted or not.
135 		 */
136 		sprint(buf, "AT+FET=%d", argc == 0? 2: 0);
137 		if(command(m, buf) != Eok)
138 			goto buggery;
139 		switch(response(m, 20)){
140 		case Rok:
141 			break;
142 		case Rhangup:
143 			if(m->fhng == 0 && argc == 0)
144 				break;
145 			r = seterror(m, Eproto);
146 			goto buggery;
147 		default:
148 			r = seterror(m, Enoresponse);
149 			goto buggery;
150 		}
151 
152 		if((m->valid & Vfpts) == 0 || m->fpts[0] != 1){
153 			r = seterror(m, Eproto);
154 			goto buggery;
155 		}
156 
157 		Bterm(m->bp);
158 		m->pageno++;
159 		argv++;
160 	}
161 okexit:
162 	xonoff(m, 0);
163 	return Eok;
164 
165 buggery:
166 	xonoff(m, 0);
167 	Bterm(m->bp);
168 	command(m, "AT+FK");
169 	response(m, 5);
170 	return r;
171 }
172