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