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