xref: /plan9/sys/src/cmd/fax/fax2receive.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
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 static char buf[102400];
8219b2ee8SDavid du Colombier 
9219b2ee8SDavid du Colombier static int
page(Modem * m,char * spool)10219b2ee8SDavid du Colombier page(Modem *m, char *spool)
11219b2ee8SDavid du Colombier {
12219b2ee8SDavid du Colombier 	int count, r;
13219b2ee8SDavid du Colombier 	char c;
14219b2ee8SDavid du Colombier 
15219b2ee8SDavid du Colombier 	/*
16219b2ee8SDavid du Colombier 	 * Start data reception. We should receive CONNECT in response
17219b2ee8SDavid du Colombier 	 * to +FDR, then data reception starts when we send DC2.
18219b2ee8SDavid du Colombier 	 */
19219b2ee8SDavid du Colombier 	m->valid &= ~(Vfhng|Vfet|Vfpts);
20219b2ee8SDavid du Colombier 	if(command(m, "AT+FDR") != Eok)
21219b2ee8SDavid du Colombier 		return Esys;
22219b2ee8SDavid du Colombier 
23219b2ee8SDavid du Colombier 	switch(response(m, 30)){
24219b2ee8SDavid du Colombier 
25219b2ee8SDavid du Colombier 	case Rconnect:
26219b2ee8SDavid du Colombier 		m->phase = 'C';
27219b2ee8SDavid du Colombier 		if((r = createfaxfile(m, spool)) != Eok)
28219b2ee8SDavid du Colombier 			return r;
29219b2ee8SDavid du Colombier 		if((r = putmchar(m, "\022")) != Eok)
30219b2ee8SDavid du Colombier 			return r;
31219b2ee8SDavid du Colombier 		break;
32219b2ee8SDavid du Colombier 
33219b2ee8SDavid du Colombier 	case Rhangup:
34219b2ee8SDavid du Colombier 		return Eok;
35219b2ee8SDavid du Colombier 
36219b2ee8SDavid du Colombier 	default:
37219b2ee8SDavid du Colombier 		return seterror(m, Eattn);
38219b2ee8SDavid du Colombier 	}
39219b2ee8SDavid du Colombier 
40219b2ee8SDavid du Colombier 	/*
41219b2ee8SDavid du Colombier 	 * Receive data.
42219b2ee8SDavid du Colombier 	 */
43219b2ee8SDavid du Colombier 	verbose("starting page %d", m->pageno);
44219b2ee8SDavid du Colombier 	count = 0;
45219b2ee8SDavid du Colombier 	while((r = getmchar(m, &c, 6)) == Eok){
46219b2ee8SDavid du Colombier 		if(c == '\020'){
47219b2ee8SDavid du Colombier 			if((r = getmchar(m, &c, 3)) != Eok)
48219b2ee8SDavid du Colombier 				break;
49219b2ee8SDavid du Colombier 			if(c == '\003')
50219b2ee8SDavid du Colombier 				break;
51219b2ee8SDavid du Colombier 			if(c != '\020'){
52219b2ee8SDavid du Colombier 				verbose("B%2.2ux", c);
53219b2ee8SDavid du Colombier 				continue;
54219b2ee8SDavid du Colombier 			}
55219b2ee8SDavid du Colombier 		}
56219b2ee8SDavid du Colombier 		buf[count++] = c;
57219b2ee8SDavid du Colombier 		if(count >= sizeof(buf)){
58*7dd7cddfSDavid du Colombier 			if(write(m->pagefd, buf, count) < 0){
59219b2ee8SDavid du Colombier 				close(m->pagefd);
60219b2ee8SDavid du Colombier 				return seterror(m, Esys);
61219b2ee8SDavid du Colombier 			}
62219b2ee8SDavid du Colombier 			count = 0;
63219b2ee8SDavid du Colombier 		}
64219b2ee8SDavid du Colombier 	}
65219b2ee8SDavid du Colombier 	verbose("page %d done, count %d", m->pageno, count);
66219b2ee8SDavid du Colombier 	if(count && write(m->pagefd, buf, count) < 0){
67219b2ee8SDavid du Colombier 		close(m->pagefd);
68219b2ee8SDavid du Colombier 		return seterror(m, Esys);
69219b2ee8SDavid du Colombier 	}
70219b2ee8SDavid du Colombier 	if(r != Eok)
71219b2ee8SDavid du Colombier 		return r;
72219b2ee8SDavid du Colombier 
73219b2ee8SDavid du Colombier 	/*
74219b2ee8SDavid du Colombier 	 * Wait for either OK or ERROR.
75219b2ee8SDavid du Colombier 	 */
76219b2ee8SDavid du Colombier 	switch(r = response(m, 20)){
77219b2ee8SDavid du Colombier 
78219b2ee8SDavid du Colombier 	case Rok:
79219b2ee8SDavid du Colombier 	case Rrerror:
80219b2ee8SDavid du Colombier 		return Eok;
81219b2ee8SDavid du Colombier 
82219b2ee8SDavid du Colombier 	default:
83219b2ee8SDavid du Colombier 		verbose("page: response %d", r);
84219b2ee8SDavid du Colombier 		return Eproto;
85219b2ee8SDavid du Colombier 	}
86219b2ee8SDavid du Colombier }
87219b2ee8SDavid du Colombier 
88219b2ee8SDavid du Colombier static int
receive(Modem * m,char * spool)89219b2ee8SDavid du Colombier receive(Modem *m, char *spool)
90219b2ee8SDavid du Colombier {
91219b2ee8SDavid du Colombier 	int r;
92219b2ee8SDavid du Colombier 
93219b2ee8SDavid du Colombier    loop:
94219b2ee8SDavid du Colombier 	switch(r = page(m, spool)){
95219b2ee8SDavid du Colombier 
96219b2ee8SDavid du Colombier 	case Eok:
97219b2ee8SDavid du Colombier 		/*
98219b2ee8SDavid du Colombier 		 * Check we have a valid page reponse.
99219b2ee8SDavid du Colombier 		 */
100219b2ee8SDavid du Colombier 		if((m->valid & Vfhng) == 0 && (m->valid & (Vfet|Vfpts)) != (Vfet|Vfpts)){
101219b2ee8SDavid du Colombier 			verbose("receive: invalid page reponse: #%4.4ux", m->valid);
102219b2ee8SDavid du Colombier 			return seterror(m, Eproto);
103219b2ee8SDavid du Colombier 		}
104219b2ee8SDavid du Colombier 
105219b2ee8SDavid du Colombier 		/*
106219b2ee8SDavid du Colombier 		 * Was the page successfully received?
107219b2ee8SDavid du Colombier 		 * If not, try again.
108219b2ee8SDavid du Colombier 		 */
109219b2ee8SDavid du Colombier 		if((m->valid & Vfpts) && m->fpts[0] != 1)
110219b2ee8SDavid du Colombier 			goto loop;
111219b2ee8SDavid du Colombier 
112219b2ee8SDavid du Colombier 		/*
113219b2ee8SDavid du Colombier 		 * Another page of the same document, a new document
114219b2ee8SDavid du Colombier 		 * or no more pages.
115219b2ee8SDavid du Colombier 		 * If no more pages we still have to get the FHNG, so
116219b2ee8SDavid du Colombier 		 * the code is just the same as if there was another
117219b2ee8SDavid du Colombier 		 * page.
118219b2ee8SDavid du Colombier 		 */
119219b2ee8SDavid du Colombier 		if(m->valid & Vfet){
120219b2ee8SDavid du Colombier 			switch(m->fet){
121219b2ee8SDavid du Colombier 
122219b2ee8SDavid du Colombier 			case 0:				/* another page */
123219b2ee8SDavid du Colombier 			case 2:				/* no more pages */
124219b2ee8SDavid du Colombier 				m->pageno++;
125219b2ee8SDavid du Colombier 				goto loop;
126219b2ee8SDavid du Colombier 
127219b2ee8SDavid du Colombier 			case 1:				/* new document */
128219b2ee8SDavid du Colombier 				/*
129219b2ee8SDavid du Colombier 				 * Bug: currently no way to run the
130219b2ee8SDavid du Colombier 				 * fax-received process for this, so it
131219b2ee8SDavid du Colombier 				 * just stays queued.
132219b2ee8SDavid du Colombier 				 */
133219b2ee8SDavid du Colombier 				faxrlog(m, Eok);
134219b2ee8SDavid du Colombier 				m->pageno = 1;
135219b2ee8SDavid du Colombier 				m->time = time(0);
136219b2ee8SDavid du Colombier 				m->pid = getpid();
137219b2ee8SDavid du Colombier 				goto loop;
138219b2ee8SDavid du Colombier 			}
139219b2ee8SDavid du Colombier 
140219b2ee8SDavid du Colombier 			verbose("receive: invalid FET: %d", m->fet);
141219b2ee8SDavid du Colombier 			return seterror(m, Eproto);
142219b2ee8SDavid du Colombier 		}
143219b2ee8SDavid du Colombier 
144219b2ee8SDavid du Colombier 		/*
145219b2ee8SDavid du Colombier 		 * All done or hangup error.
146219b2ee8SDavid du Colombier 		 * On error remove all pages in the current document.
147219b2ee8SDavid du Colombier 		 * Yik.
148219b2ee8SDavid du Colombier 		 */
149219b2ee8SDavid du Colombier 		if(m->valid & Vfhng){
150219b2ee8SDavid du Colombier 			if(m->fhng == 0)
151219b2ee8SDavid du Colombier 				return Eok;
152219b2ee8SDavid du Colombier 			verbose("receive: FHNG: %d", m->fhng);
153219b2ee8SDavid du Colombier 			/*
154219b2ee8SDavid du Colombier 			for(r = 1; r <= m->pageno; r++){
155219b2ee8SDavid du Colombier 				char pageid[128];
156219b2ee8SDavid du Colombier 
157219b2ee8SDavid du Colombier 				setpageid(pageid, spool, m->time, m->pid, r);
158219b2ee8SDavid du Colombier 				remove(pageid);
159219b2ee8SDavid du Colombier 			}
160219b2ee8SDavid du Colombier 			 */
161219b2ee8SDavid du Colombier 			return seterror(m, Eattn);
162219b2ee8SDavid du Colombier 		}
163219b2ee8SDavid du Colombier 		/*FALLTHROUGH*/
164219b2ee8SDavid du Colombier 
165219b2ee8SDavid du Colombier 	default:
166219b2ee8SDavid du Colombier 		return r;
167219b2ee8SDavid du Colombier 	}
168219b2ee8SDavid du Colombier }
169219b2ee8SDavid du Colombier 
170219b2ee8SDavid du Colombier int
faxreceive(Modem * m,char * spool)171219b2ee8SDavid du Colombier faxreceive(Modem *m, char *spool)
172219b2ee8SDavid du Colombier {
173219b2ee8SDavid du Colombier 	int r;
174219b2ee8SDavid du Colombier 
175219b2ee8SDavid du Colombier 	verbose("faxdaemon");
176219b2ee8SDavid du Colombier 	if((r = initfaxmodem(m)) != Eok)
177219b2ee8SDavid du Colombier 		return r;
178219b2ee8SDavid du Colombier 
179219b2ee8SDavid du Colombier 	/*
180219b2ee8SDavid du Colombier 	 *  assume that the phone has been answered and
181219b2ee8SDavid du Colombier 	 *  we have received +FCON
182219b2ee8SDavid du Colombier 	 */
183219b2ee8SDavid du Colombier 	m->pageno = 1;
184219b2ee8SDavid du Colombier 	m->time = time(0);
185219b2ee8SDavid du Colombier 	m->pid = getpid();
186219b2ee8SDavid du Colombier 	fcon(m);
187219b2ee8SDavid du Colombier 
188219b2ee8SDavid du Colombier 	/*
189219b2ee8SDavid du Colombier 	 * I wish I knew how to set the default parameters on the
190219b2ee8SDavid du Colombier 	 * MT1432 modem (+FIP in Class 2.0).
191219b2ee8SDavid du Colombier 	 */
192219b2ee8SDavid du Colombier 	return receive(m, spool);
193219b2ee8SDavid du Colombier }
194