xref: /netbsd-src/usr.bin/tip/aculib/hayes.c (revision 81b108b45f75f89f1e3ffad9fb6f074e771c0935)
1 /*	$NetBSD: hayes.c,v 1.4 1995/10/29 00:49:54 pk 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.4 1995/10/29 00:49:54 pk 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 #include <termios.h>
69 #include <sys/ioctl.h>
70 
71 #define	min(a,b)	((a < b) ? a : b)
72 
73 static	void sigALRM();
74 static	int timeout = 0;
75 static	jmp_buf timeoutbuf;
76 static 	char gobble();
77 #define DUMBUFLEN	40
78 static char dumbuf[DUMBUFLEN];
79 
80 #define	DIALING		1
81 #define IDLE		2
82 #define CONNECTED	3
83 #define	FAILED		4
84 static	int state = IDLE;
85 
86 hay_dialer(num, acu)
87 	register char *num;
88 	char *acu;
89 {
90 	register char *cp;
91 	register int connected = 0;
92 	char dummy;
93 	struct termios cntrl;
94 #ifdef ACULOG
95 	char line[80];
96 #endif
97 	if (hay_sync() == 0)		/* make sure we can talk to the modem */
98 		return(0);
99 	if (boolean(value(VERBOSE)))
100 		printf("\ndialing...");
101 	fflush(stdout);
102 	tcgetattr(FD, &cntrl);
103 	cntrl.c_cflag |= HUPCL;
104 	tcsetattr(FD, TCSANOW, &cntrl);
105 	tcflush(FD, TCIOFLUSH);
106 	write(FD, "ATv0\r", 5);	/* tell modem to use short status codes */
107 	gobble("\r");
108 	gobble("\r");
109 	write(FD, "ATTD", 4);	/* send dial command */
110 	write(FD, num, strlen(num));
111 	state = DIALING;
112 	write(FD, "\r", 1);
113 	connected = 0;
114 	if (gobble("\r")) {
115 		if ((dummy = gobble("01234")) != '1')
116 			error_rep(dummy);
117 		else
118 			connected = 1;
119 	}
120 	if (connected)
121 		state = CONNECTED;
122 	else {
123 		state = FAILED;
124 		return (connected);	/* lets get out of here.. */
125 	}
126 	tcflush(FD, TCIOFLUSH);
127 #ifdef ACULOG
128 	if (timeout) {
129 		sprintf(line, "%d second dial timeout",
130 			number(value(DIALTIMEOUT)));
131 		logent(value(HOST), num, "hayes", line);
132 	}
133 #endif
134 	if (timeout)
135 		hay_disconnect();	/* insurance */
136 	return (connected);
137 }
138 
139 
140 hay_disconnect()
141 {
142 	char c;
143 	int len, rlen;
144 
145 	/* first hang up the modem*/
146 #ifdef DEBUG
147 	printf("\rdisconnecting modem....\n\r");
148 #endif
149 	ioctl(FD, TIOCCDTR, 0);
150 	sleep(1);
151 	ioctl(FD, TIOCSDTR, 0);
152 	goodbye();
153 }
154 
155 hay_abort()
156 {
157 
158 	char c;
159 
160 	write(FD, "\r", 1);	/* send anything to abort the call */
161 	hay_disconnect();
162 }
163 
164 static void
165 sigALRM()
166 {
167 
168 	printf("\07timeout waiting for reply\n\r");
169 	timeout = 1;
170 	longjmp(timeoutbuf, 1);
171 }
172 
173 static char
174 gobble(match)
175 	register char *match;
176 {
177 	char c;
178 	sig_t f;
179 	int i, status = 0;
180 
181 	f = signal(SIGALRM, sigALRM);
182 	timeout = 0;
183 #ifdef DEBUG
184 	printf("\ngobble: waiting for %s\n", match);
185 #endif
186 	do {
187 		if (setjmp(timeoutbuf)) {
188 			signal(SIGALRM, f);
189 			return (0);
190 		}
191 		alarm(number(value(DIALTIMEOUT)));
192 		read(FD, &c, 1);
193 		alarm(0);
194 		c &= 0177;
195 #ifdef DEBUG
196 		printf("%c 0x%x ", c, c);
197 #endif
198 		for (i = 0; i < strlen(match); i++)
199 			if (c == match[i])
200 				status = c;
201 	} while (status == 0);
202 	signal(SIGALRM, SIG_DFL);
203 #ifdef DEBUG
204 	printf("\n");
205 #endif
206 	return (status);
207 }
208 
209 error_rep(c)
210 	register char c;
211 {
212 	printf("\n\r");
213 	switch (c) {
214 
215 	case '0':
216 		printf("OK");
217 		break;
218 
219 	case '1':
220 		printf("CONNECT");
221 		break;
222 
223 	case '2':
224 		printf("RING");
225 		break;
226 
227 	case '3':
228 		printf("NO CARRIER");
229 		break;
230 
231 	case '4':
232 		printf("ERROR in input");
233 		break;
234 
235 	case '5':
236 		printf("CONNECT 1200");
237 		break;
238 
239 	default:
240 		printf("Unknown Modem error: %c (0x%x)", c, c);
241 	}
242 	printf("\n\r");
243 	return;
244 }
245 
246 /*
247  * set modem back to normal verbose status codes.
248  */
249 goodbye()
250 {
251 	int len, rlen;
252 	char c;
253 
254 	tcflush(FD, TCIOFLUSH);
255 	if (hay_sync()) {
256 		sleep(1);
257 #ifndef DEBUG
258 		tcflush(FD, TCIOFLUSH);
259 #endif
260 		write(FD, "ATH0\r", 5);		/* insurance */
261 #ifndef DEBUG
262 		c = gobble("03");
263 		if (c != '0' && c != '3') {
264 			printf("cannot hang up modem\n\r");
265 			printf("please use 'tip dialer' to make sure the line is hung up\n\r");
266 		}
267 #endif
268 		sleep(1);
269 		ioctl(FD, FIONREAD, &len);
270 #ifdef DEBUG
271 		printf("goodbye1: len=%d -- ", len);
272 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
273 		dumbuf[rlen] = '\0';
274 		printf("read (%d): %s\r\n", rlen, dumbuf);
275 #endif
276 		write(FD, "ATv1\r", 5);
277 		sleep(1);
278 #ifdef DEBUG
279 		ioctl(FD, FIONREAD, &len);
280 		printf("goodbye2: len=%d -- ", len);
281 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
282 		dumbuf[rlen] = '\0';
283 		printf("read (%d): %s\r\n", rlen, dumbuf);
284 #endif
285 	}
286 	tcflush(FD, TCIOFLUSH);
287 	ioctl(FD, TIOCCDTR, 0);		/* clear DTR (insurance) */
288 	close(FD);
289 }
290 
291 #define MAXRETRY	5
292 
293 hay_sync()
294 {
295 	int len, retry = 0;
296 
297 	while (retry++ <= MAXRETRY) {
298 		write(FD, "AT\r", 3);
299 		sleep(1);
300 		ioctl(FD, FIONREAD, &len);
301 		if (len) {
302 			len = read(FD, dumbuf, min(len, DUMBUFLEN));
303 			if (index(dumbuf, '0') ||
304 		   	(index(dumbuf, 'O') && index(dumbuf, 'K')))
305 				return(1);
306 #ifdef DEBUG
307 			dumbuf[len] = '\0';
308 			printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
309 #endif
310 		}
311 		ioctl(FD, TIOCCDTR, 0);
312 		ioctl(FD, TIOCSDTR, 0);
313 	}
314 	printf("Cannot synchronize with hayes...\n\r");
315 	return(0);
316 }
317