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