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