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