xref: /freebsd/usr.bin/tip/libacu/hayes.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*
2  * Copyright (c) 1983, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char sccsid[] = "@(#)hayes.c	8.1 (Berkeley) 6/6/93";
36 #endif /* not lint */
37 
38 /*
39  * Routines for calling up on a Hayes Modem
40  * (based on the old VenTel driver).
41  * The modem is expected to be strapped for "echo".
42  * Also, the switches enabling the DTR and CD lines
43  * must be set correctly.
44  * NOTICE:
45  * The easy way to hang up a modem is always simply to
46  * clear the DTR signal. However, if the +++ sequence
47  * (which switches the modem back to local mode) is sent
48  * before modem is hung up, removal of the DTR signal
49  * has no effect (except that it prevents the modem from
50  * recognizing commands).
51  * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984)
52  */
53 /*
54  * TODO:
55  * It is probably not a good idea to switch the modem
56  * state between 'verbose' and terse (status messages).
57  * This should be kicked out and we should use verbose
58  * mode only. This would make it consistent with normal
59  * interactive use thru the command 'tip dialer'.
60  */
61 #include "tipconf.h"
62 #include "tip.h"
63 
64 #define	min(a,b)	((a < b) ? a : b)
65 
66 static	void sigALRM();
67 static	int timeout = 0;
68 static	jmp_buf timeoutbuf;
69 static 	char gobble();
70 #define DUMBUFLEN	40
71 static char dumbuf[DUMBUFLEN];
72 
73 #define	DIALING		1
74 #define IDLE		2
75 #define CONNECTED	3
76 #define	FAILED		4
77 static	int state = IDLE;
78 
79 hay_dialer(num, acu)
80 	register char *num;
81 	char *acu;
82 {
83 	register char *cp;
84 	register int connected = 0;
85 	char dummy;
86 #if ACULOG
87 	char line[80];
88 #endif
89 	if (hay_sync() == 0)		/* make sure we can talk to the modem */
90 		return(0);
91 	if (boolean(value(VERBOSE)))
92 		printf("\ndialing...");
93 	fflush(stdout);
94 	acu_hupcl ();
95 	acu_flush ();
96 	write(FD, "ATv0\r", 5);	/* tell modem to use short status codes */
97 	gobble("\r");
98 	gobble("\r");
99 	write(FD, "ATTD", 4);	/* send dial command */
100 	write(FD, num, strlen(num));
101 	state = DIALING;
102 	write(FD, "\r", 1);
103 	connected = 0;
104 	if (gobble("\r")) {
105 		if ((dummy = gobble("01234")) != '1')
106 			error_rep(dummy);
107 		else
108 			connected = 1;
109 	}
110 	if (connected)
111 		state = CONNECTED;
112 	else {
113 		state = FAILED;
114 		return (connected);	/* lets get out of here.. */
115 	}
116 	ioctl(FD, TIOCFLUSH, 0);
117 #if ACULOG
118 	if (timeout) {
119 		sprintf(line, "%d second dial timeout",
120 			number(value(DIALTIMEOUT)));
121 		logent(value(HOST), num, "hayes", line);
122 	}
123 #endif
124 	if (timeout)
125 		hay_disconnect();	/* insurance */
126 	return (connected);
127 }
128 
129 
130 hay_disconnect()
131 {
132 	char c;
133 	int len, rlen;
134 
135 	/* first hang up the modem*/
136 #ifdef DEBUG
137 	printf("\rdisconnecting modem....\n\r");
138 #endif
139 	ioctl(FD, TIOCCDTR, 0);
140 	sleep(1);
141 	ioctl(FD, TIOCSDTR, 0);
142 	goodbye();
143 }
144 
145 hay_abort()
146 {
147 
148 	char c;
149 
150 	write(FD, "\r", 1);	/* send anything to abort the call */
151 	hay_disconnect();
152 }
153 
154 static void
155 sigALRM()
156 {
157 
158 	printf("\07timeout waiting for reply\n\r");
159 	timeout = 1;
160 	longjmp(timeoutbuf, 1);
161 }
162 
163 static char
164 gobble(match)
165 	register char *match;
166 {
167 	char c;
168 	sig_t f;
169 	int i, status = 0;
170 
171 	f = signal(SIGALRM, sigALRM);
172 	timeout = 0;
173 #ifdef DEBUG
174 	printf("\ngobble: waiting for %s\n", match);
175 #endif
176 	do {
177 		if (setjmp(timeoutbuf)) {
178 			signal(SIGALRM, f);
179 			return (0);
180 		}
181 		alarm(number(value(DIALTIMEOUT)));
182 		read(FD, &c, 1);
183 		alarm(0);
184 		c &= 0177;
185 #ifdef DEBUG
186 		printf("%c 0x%x ", c, c);
187 #endif
188 		for (i = 0; i < strlen(match); i++)
189 			if (c == match[i])
190 				status = c;
191 	} while (status == 0);
192 	signal(SIGALRM, SIG_DFL);
193 #ifdef DEBUG
194 	printf("\n");
195 #endif
196 	return (status);
197 }
198 
199 error_rep(c)
200 	register char c;
201 {
202 	printf("\n\r");
203 	switch (c) {
204 
205 	case '0':
206 		printf("OK");
207 		break;
208 
209 	case '1':
210 		printf("CONNECT");
211 		break;
212 
213 	case '2':
214 		printf("RING");
215 		break;
216 
217 	case '3':
218 		printf("NO CARRIER");
219 		break;
220 
221 	case '4':
222 		printf("ERROR in input");
223 		break;
224 
225 	case '5':
226 		printf("CONNECT 1200");
227 		break;
228 
229 	default:
230 		printf("Unknown Modem error: %c (0x%x)", c, c);
231 	}
232 	printf("\n\r");
233 	return;
234 }
235 
236 /*
237  * set modem back to normal verbose status codes.
238  */
239 goodbye()
240 {
241 	int len, rlen;
242 	char c;
243 
244 	ioctl(FD, TIOCFLUSH, &len);	/* get rid of trash */
245 	if (hay_sync()) {
246 		sleep(1);
247 #ifndef DEBUG
248 		ioctl(FD, TIOCFLUSH, 0);
249 #endif
250 		write(FD, "ATH0\r", 5);		/* insurance */
251 #ifndef DEBUG
252 		c = gobble("03");
253 		if (c != '0' && c != '3') {
254 			printf("cannot hang up modem\n\r");
255 			printf("please use 'tip dialer' to make sure the line is hung up\n\r");
256 		}
257 #endif
258 		sleep(1);
259 		ioctl(FD, FIONREAD, &len);
260 #ifdef DEBUG
261 		printf("goodbye1: len=%d -- ", len);
262 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
263 		dumbuf[rlen] = '\0';
264 		printf("read (%d): %s\r\n", rlen, dumbuf);
265 #endif
266 		write(FD, "ATv1\r", 5);
267 		sleep(1);
268 #ifdef DEBUG
269 		ioctl(FD, FIONREAD, &len);
270 		printf("goodbye2: len=%d -- ", len);
271 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
272 		dumbuf[rlen] = '\0';
273 		printf("read (%d): %s\r\n", rlen, dumbuf);
274 #endif
275 	}
276 	ioctl(FD, TIOCFLUSH, 0);	/* clear the input buffer */
277 	ioctl(FD, TIOCCDTR, 0);		/* clear DTR (insurance) */
278 	close(FD);
279 }
280 
281 #define MAXRETRY	5
282 
283 hay_sync()
284 {
285 	int len, retry = 0;
286 
287 	while (retry++ <= MAXRETRY) {
288 		write(FD, "AT\r", 3);
289 		sleep(1);
290 		ioctl(FD, FIONREAD, &len);
291 		if (len) {
292 			len = read(FD, dumbuf, min(len, DUMBUFLEN));
293 			if (index(dumbuf, '0') ||
294 		   	(index(dumbuf, 'O') && index(dumbuf, 'K')))
295 				return(1);
296 #ifdef DEBUG
297 			dumbuf[len] = '\0';
298 			printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
299 #endif
300 		}
301 		ioctl(FD, TIOCCDTR, 0);
302 		ioctl(FD, TIOCSDTR, 0);
303 	}
304 	printf("Cannot synchronize with hayes...\n\r");
305 	return(0);
306 }
307